module ysyx_22040729(
  input               clock,
  input               reset,
  input	              io_interrupt,
  input	              io_master_awready,
  output	            io_master_awvalid,
  output [3:0]        io_master_awid,
  output [31:0]	      io_master_awaddr,
  output [7:0]        io_master_awlen,
  output [2:0]        io_master_awsize,
  output [1:0]        io_master_awburst,
  input	              io_master_wready,
  output	            io_master_wvalid,
  output [63:0]       io_master_wdata,
  output [7:0]	      io_master_wstrb,
  output	            io_master_wlast,
  output	            io_master_bready,
  input	              io_master_bvalid,
  input  [3:0]	      io_master_bid,
  input  [1:0]	      io_master_bresp,
  input	              io_master_arready,
  output	            io_master_arvalid,
  output [3:0]	      io_master_arid,
  output [31:0]	      io_master_araddr,
  output [7:0]	      io_master_arlen,
  output [2:0]	      io_master_arsize,
  output [1:0]	      io_master_arburst,
  output	            io_master_rready,
  input	              io_master_rvalid,
  input  [3:0]	      io_master_rid,
  input  [1:0]	      io_master_rresp,
  input  [63:0]	      io_master_rdata,
  input	              io_master_rlast,
  output	            io_slave_awready,
  input	              io_slave_awvalid,
  input  [3:0]	      io_slave_awid,
  input  [31:0]	      io_slave_awaddr,
  input  [7:0]	      io_slave_awlen,
  input  [2:0]	      io_slave_awsize,
  input  [1:0]	      io_slave_awburst,
  output	            io_slave_wready,
  input	              io_slave_wvalid,
  input  [63:0]	      io_slave_wdata,
  input  [7:0]	      io_slave_wstrb,
  input	              io_slave_wlast,
  input	              io_slave_bready,
  output 	            io_slave_bvalid,
  output [3:0]	      io_slave_bid,
  output [1:0]	      io_slave_bresp,
  output	            io_slave_arready,
  input  	            io_slave_arvalid,
  input  [3:0]	      io_slave_arid,
  input  [31:0]	      io_slave_araddr,
  input  [7:0]	      io_slave_arlen,
  input  [2:0]	      io_slave_arsize,
  input  [1:0]	      io_slave_arburst,
  input	              io_slave_rready,
  output	            io_slave_rvalid,
  output [3:0]	      io_slave_rid,
  output [1:0]	      io_slave_rresp,
  output [63:0]	      io_slave_rdata,
  output	            io_slave_rlast,
  output [5:0]	      io_sram0_addr,
  output	            io_sram0_cen,
  output	            io_sram0_wen,
  output [127:0]      io_sram0_wmask,
  output [127:0]      io_sram0_wdata,
  input  [127:0]      io_sram0_rdata,
  output [5:0]	      io_sram1_addr,
  output	            io_sram1_cen,
  output	            io_sram1_wen,
  output [127:0]      io_sram1_wmask,
  output [127:0]      io_sram1_wdata,
  input  [127:0]      io_sram1_rdata,
  output [5:0]	      io_sram2_addr,
  output	            io_sram2_cen,
  output	            io_sram2_wen,
  output [127:0]      io_sram2_wmask,
  output [127:0]      io_sram2_wdata,
  input  [127:0]      io_sram2_rdata,
  output [5:0]	      io_sram3_addr,
  output	            io_sram3_cen,
  output	            io_sram3_wen,
  output [127:0]      io_sram3_wmask,
  output [127:0]      io_sram3_wdata,
  input  [127:0]      io_sram3_rdata,
  output [5:0]	      io_sram4_addr,
  output	            io_sram4_cen,
  output	            io_sram4_wen,
  output [127:0]      io_sram4_wmask,
  output [127:0]      io_sram4_wdata,
  input  [127:0]      io_sram4_rdata,
  output [5:0]	      io_sram5_addr,
  output	            io_sram5_cen,
  output	            io_sram5_wen,
  output [127:0]      io_sram5_wmask,
  output [127:0]      io_sram5_wdata,
  input  [127:0]      io_sram5_rdata,
  output [5:0]	      io_sram6_addr,
  output	            io_sram6_cen,
  output	            io_sram6_wen,
  output [127:0]      io_sram6_wmask,
  output [127:0]      io_sram6_wdata,
  input  [127:0]      io_sram6_rdata,
  output [5:0]	      io_sram7_addr,
  output	            io_sram7_cen,
  output	            io_sram7_wen,
  output [127:0]      io_sram7_wmask,
  output [127:0]      io_sram7_wdata,
  input  [127:0]      io_sram7_rdata
);
localparam DATA_WIDTH = 64;
localparam ADDR_WIDTH = 32;
localparam INST_WIDTH = 32;
localparam REG_ADDR_W = 5;
localparam RESET_ADDR = 64'h30000000;
localparam RW_DATA_WIDTH    = 256;
localparam AXI_DATA_WIDTH   = 64;
localparam AXI_ADDR_WIDTH   = 32;
localparam AXI_ID_WIDTH     = 4;
localparam AXI_STRB_WIDTH   = AXI_DATA_WIDTH/8;

 wire if_valid, if_ready, mem_valid, mem_ready, mem_wen;
 wire fence;
 wire [2:0] mem_size;
 wire [INST_WIDTH-1:0]    if_data_read;
 wire [ADDR_WIDTH-1:0]    if_addr;
 wire [ADDR_WIDTH-1:0]    mem_addr;
 wire [DATA_WIDTH-1:0]    mem_data_read, mem_data_write;


ysyx_22040729_CPU #(
  .DATA_WIDTH(DATA_WIDTH),
  .ADDR_WIDTH(ADDR_WIDTH),
  .INST_WIDTH(INST_WIDTH),
  .REG_ADDR_W(REG_ADDR_W),
  .RESET_ADDR(RESET_ADDR)
)cpu_inst(
  .clock       (clock),
  .reset       (reset),
  .fence_o     (fence),

  .mem_valid       (mem_valid),
  .mem_ready       (mem_ready),
  .mem_data_read   (mem_data_read),
  .mem_data_write  (mem_data_write),
  .mem_addr        (mem_addr),
  .mem_size        (mem_size),
  .mem_wen         (mem_wen),

  .if_valid        (if_valid),
  .if_ready        (if_ready),
  .if_data_read    (if_data_read),
  .if_addr         (if_addr)
);

//cache
wire [AXI_ADDR_WIDTH-1:0] r_addr_c2a, w_addr_c2a;
wire [2:0] r_size_c2a, w_size_c2a;
wire r_valid_c2a, r_ready_c2a, w_valid_c2a, w_ready_c2a;
wire [RW_DATA_WIDTH-1:0] r_data_c2a, w_data_c2a;

ysyx_22040729_Cache #(
  .RW_DATA_WIDTH (RW_DATA_WIDTH),
  .AXI_ADDR_WIDTH(AXI_ADDR_WIDTH)
)cache_inst(
  .i_addr_i           (if_addr),
  .i_valid_i          (if_valid),
  .i_rdata_o          (if_data_read),
  .i_ready_o          (if_ready),

  .d_addr_i           (mem_addr),
  .d_wen_i            (mem_wen),
  .d_size_i           (mem_size),
  .d_wdata_i          (mem_data_write),
  .d_rdata_o          (mem_data_read),
  .d_valid_i          (mem_valid),
  .d_ready_o          (mem_ready),


  .r_addr_o           (r_addr_c2a ),
  .r_size_o           (r_size_c2a ),
  .r_valid_o          (r_valid_c2a),
  .r_ready_i          (r_ready_c2a),
  .r_data_i           (r_data_c2a ),

  .w_addr_o           (w_addr_c2a ),
  .w_data_o           (w_data_c2a ),
  .w_size_o           (w_size_c2a ),
  .w_valid_o          (w_valid_c2a),
  .w_ready_i          (w_ready_c2a),


  .io_sram0_addr      (io_sram0_addr ),
  .io_sram0_cen       (io_sram0_cen  ),
  .io_sram0_wen       (io_sram0_wen  ),
  .io_sram0_wmask     (io_sram0_wmask),
  .io_sram0_wdata     (io_sram0_wdata),
  .io_sram0_rdata     (io_sram0_rdata),

  .io_sram1_addr      (io_sram1_addr ),
  .io_sram1_cen       (io_sram1_cen  ),
  .io_sram1_wen       (io_sram1_wen  ),
  .io_sram1_wmask     (io_sram1_wmask),
  .io_sram1_wdata     (io_sram1_wdata),
  .io_sram1_rdata     (io_sram1_rdata),

  .io_sram2_addr      (io_sram2_addr ),
  .io_sram2_cen       (io_sram2_cen  ),
  .io_sram2_wen       (io_sram2_wen  ),
  .io_sram2_wmask     (io_sram2_wmask),
  .io_sram2_wdata     (io_sram2_wdata),
  .io_sram2_rdata     (io_sram2_rdata),

  .io_sram3_addr      (io_sram3_addr ),
  .io_sram3_cen       (io_sram3_cen  ),
  .io_sram3_wen       (io_sram3_wen  ),
  .io_sram3_wmask     (io_sram3_wmask),
  .io_sram3_wdata     (io_sram3_wdata),
  .io_sram3_rdata     (io_sram3_rdata),
  
  .io_sram4_addr      (io_sram4_addr ),
  .io_sram4_cen       (io_sram4_cen  ),
  .io_sram4_wen       (io_sram4_wen  ),
  .io_sram4_wmask     (io_sram4_wmask),
  .io_sram4_wdata     (io_sram4_wdata),
  .io_sram4_rdata     (io_sram4_rdata),

  .io_sram5_addr      (io_sram5_addr ),
  .io_sram5_cen       (io_sram5_cen  ),
  .io_sram5_wen       (io_sram5_wen  ),
  .io_sram5_wmask     (io_sram5_wmask),
  .io_sram5_wdata     (io_sram5_wdata),
  .io_sram5_rdata     (io_sram5_rdata),

  .io_sram6_addr      (io_sram6_addr ),
  .io_sram6_cen       (io_sram6_cen  ),
  .io_sram6_wen       (io_sram6_wen  ),
  .io_sram6_wmask     (io_sram6_wmask),
  .io_sram6_wdata     (io_sram6_wdata),
  .io_sram6_rdata     (io_sram6_rdata),

  .io_sram7_addr      (io_sram7_addr ),
  .io_sram7_cen       (io_sram7_cen  ),
  .io_sram7_wen       (io_sram7_wen  ),
  .io_sram7_wmask     (io_sram7_wmask),
  .io_sram7_wdata     (io_sram7_wdata),
  .io_sram7_rdata     (io_sram7_rdata),

  .fence_i            (fence),
  .clock              (clock),
  .reset              (reset)
);


//axi

ysyx_22040729_AXI # (
    .RW_DATA_WIDTH (RW_DATA_WIDTH),
    .AXI_DATA_WIDTH(AXI_DATA_WIDTH),
    .AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
    .AXI_ID_WIDTH  (AXI_ID_WIDTH  ),
    .AXI_STRB_WIDTH(AXI_STRB_WIDTH)
)AXI_inst(
    .clock              (clock),
    .reset              (reset),

	  .r_addr_i           (r_addr_c2a ),
    .r_size_i           (r_size_c2a ),
    .r_valid_i          (r_valid_c2a),
    .r_ready_o          (r_ready_c2a),
    .r_data_o           (r_data_c2a ),

    .w_addr_i           (w_addr_c2a ),
    .w_data_i           (w_data_c2a ),
    .w_size_i           (w_size_c2a ),
    .w_valid_i          (w_valid_c2a),
    .w_ready_o          (w_ready_c2a),

    .axi_aw_ready_i     (io_master_awready),      
    .axi_aw_valid_o     (io_master_awvalid),
    .axi_aw_addr_o      (io_master_awaddr ),
    .axi_aw_id_o        (io_master_awid   ),
    .axi_aw_len_o       (io_master_awlen  ),
    .axi_aw_size_o      (io_master_awsize ),
    .axi_aw_burst_o     (io_master_awburst),

    .axi_w_ready_i      (io_master_wready ),                
    .axi_w_valid_o      (io_master_wvalid ),
    .axi_w_data_o       (io_master_wdata  ),
    .axi_w_strb_o       (io_master_wstrb  ),
    .axi_w_last_o       (io_master_wlast  ),
    
    .axi_b_ready_o      (io_master_bready ),                
    .axi_b_valid_i      (io_master_bvalid ),
    .axi_b_resp_i       (io_master_bresp  ),                 
    .axi_b_id_i         (io_master_bid    ),

    .axi_ar_ready_i     (io_master_arready),                
    .axi_ar_valid_o     (io_master_arvalid),
    .axi_ar_addr_o      (io_master_araddr ),
    .axi_ar_id_o        (io_master_arid   ),
    .axi_ar_len_o       (io_master_arlen	),
    .axi_ar_size_o      (io_master_arsize ),
    .axi_ar_burst_o     (io_master_arburst),
    
    .axi_r_ready_o      (io_master_rready ),                 
    .axi_r_valid_i      (io_master_rvalid ),                
    .axi_r_resp_i       (io_master_rresp  ),
    .axi_r_data_i       (io_master_rdata  ),
    .axi_r_last_i       (io_master_rlast  ),
    .axi_r_id_i         (io_master_rid    )
);

//axi slave
//axi slave
assign io_slave_awready = '0;
assign io_slave_wready  = '0;
assign io_slave_bvalid  = '0;
assign io_slave_bid     = '0;
assign io_slave_bresp   = '0;
assign io_slave_arready = '0;
assign io_slave_rvalid  = '0;
assign io_slave_rid     = '0;
assign io_slave_rresp   = '0;
assign io_slave_rdata   = '0;
assign io_slave_rlast   = '0;

endmodule
// Burst typesAXI_BURST_TYPE_INCR
`define ysyx_22040729_AXI_BURST_TYPE_FIXED                                2'b00               //突发类型  FIFO
`define ysyx_22040729_AXI_BURST_TYPE_INCR                                 2'b01               //ram  
`define ysyx_22040729_AXI_BURST_TYPE_WRAP                                 2'b10
// Access permissions
`define ysyx_22040729_AXI_PROT_UNPRIVILEGED_ACCESS                        3'b000
`define ysyx_22040729_AXI_PROT_PRIVILEGED_ACCESS                          3'b001
`define ysyx_22040729_AXI_PROT_SECURE_ACCESS                              3'b000
`define ysyx_22040729_AXI_PROT_NON_SECURE_ACCESS                          3'b010
`define ysyx_22040729_AXI_PROT_DATA_ACCESS                                3'b000
`define ysyx_22040729_AXI_PROT_INSTRUCTION_ACCESS                         3'b100
// Memory types (AR)
`define ysyx_22040729_AXI_ARCACHE_DEVICE_NON_BUFFERABLE                   4'b0000
`define ysyx_22040729_AXI_ARCACHE_DEVICE_BUFFERABLE                       4'b0001
`define ysyx_22040729_AXI_ARCACHE_NORMAL_NON_CACHEABLE_NON_BUFFERABLE     4'b0010
`define ysyx_22040729_AXI_ARCACHE_NORMAL_NON_CACHEABLE_BUFFERABLE         4'b0011
`define ysyx_22040729_AXI_ARCACHE_WRITE_THROUGH_NO_ALLOCATE               4'b1010
`define ysyx_22040729_AXI_ARCACHE_WRITE_THROUGH_READ_ALLOCATE             4'b1110
`define ysyx_22040729_AXI_ARCACHE_WRITE_THROUGH_WRITE_ALLOCATE            4'b1010
`define ysyx_22040729_AXI_ARCACHE_WRITE_THROUGH_READ_AND_WRITE_ALLOCATE   4'b1110
`define ysyx_22040729_AXI_ARCACHE_WRITE_BACK_NO_ALLOCATE                  4'b1011
`define ysyx_22040729_AXI_ARCACHE_WRITE_BACK_READ_ALLOCATE                4'b1111
`define ysyx_22040729_AXI_ARCACHE_WRITE_BACK_WRITE_ALLOCATE               4'b1011
`define ysyx_22040729_AXI_ARCACHE_WRITE_BACK_READ_AND_WRITE_ALLOCATE      4'b1111
// Memory types (AW)
`define ysyx_22040729_AXI_AWCACHE_DEVICE_NON_BUFFERABLE                   4'b0000
`define ysyx_22040729_AXI_AWCACHE_DEVICE_BUFFERABLE                       4'b0001
`define ysyx_22040729_AXI_AWCACHE_NORMAL_NON_CACHEABLE_NON_BUFFERABLE     4'b0010
`define ysyx_22040729_AXI_AWCACHE_NORMAL_NON_CACHEABLE_BUFFERABLE         4'b0011
`define ysyx_22040729_AXI_AWCACHE_WRITE_THROUGH_NO_ALLOCATE               4'b0110
`define ysyx_22040729_AXI_AWCACHE_WRITE_THROUGH_READ_ALLOCATE             4'b0110
`define ysyx_22040729_AXI_AWCACHE_WRITE_THROUGH_WRITE_ALLOCATE            4'b1110
`define ysyx_22040729_AXI_AWCACHE_WRITE_THROUGH_READ_AND_WRITE_ALLOCATE   4'b1110
`define ysyx_22040729_AXI_AWCACHE_WRITE_BACK_NO_ALLOCATE                  4'b0111
`define ysyx_22040729_AXI_AWCACHE_WRITE_BACK_READ_ALLOCATE                4'b0111
`define ysyx_22040729_AXI_AWCACHE_WRITE_BACK_WRITE_ALLOCATE               4'b1111
`define ysyx_22040729_AXI_AWCACHE_WRITE_BACK_READ_AND_WRITE_ALLOCATE      4'b1111

`define ysyx_22040729_AXI_SIZE_BYTES_1                                    3'b000                //突发宽度一个数据的宽度
`define ysyx_22040729_AXI_SIZE_BYTES_2                                    3'b001
`define ysyx_22040729_AXI_SIZE_BYTES_4                                    3'b010
`define ysyx_22040729_AXI_SIZE_BYTES_8                                    3'b011
`define ysyx_22040729_AXI_SIZE_BYTES_16                                   3'b100
`define ysyx_22040729_AXI_SIZE_BYTES_32                                   3'b101
`define ysyx_22040729_AXI_SIZE_BYTES_64                                   3'b110
`define ysyx_22040729_AXI_SIZE_BYTES_128                                  3'b111


module ysyx_22040729_AXI # (
    parameter RW_DATA_WIDTH     = 128,
    parameter AXI_DATA_WIDTH    = 64,
    parameter AXI_ADDR_WIDTH    = 32,
    parameter AXI_ID_WIDTH      = 4,
//    parameter AXI_USER_WIDTH    = 1,
    parameter AXI_STRB_WIDTH    = AXI_DATA_WIDTH/8
)(
    input                               clock,
    input                               reset,

    //read
    input  [AXI_ADDR_WIDTH-1:0]         r_addr_i,
    input  [2:0]                        r_size_i,
	input                               r_valid_i, 
	output                              r_ready_o,  
    output [RW_DATA_WIDTH-1:0]          r_data_o,
    //write
    input  [AXI_ADDR_WIDTH-1:0]         w_addr_i,
    input  [RW_DATA_WIDTH-1:0]          w_data_i,
    input  [2:0]                        w_size_i,
    input                               w_valid_i,  
	output                              w_ready_o,



    // Advanced eXtensible Interface
    input                               axi_aw_ready_i,              
    output                              axi_aw_valid_o,
    output [AXI_ADDR_WIDTH-1:0]         axi_aw_addr_o,
    output [AXI_ID_WIDTH-1:0]           axi_aw_id_o,
    output [7:0]                        axi_aw_len_o,
    output [2:0]                        axi_aw_size_o,
    output [1:0]                        axi_aw_burst_o,
//    output [2:0]                        axi_aw_prot_o,
//    output [AXI_USER_WIDTH-1:0]         axi_aw_user_o,
//    output                              axi_aw_lock_o,
//    output [3:0]                        axi_aw_cache_o,
//    output [3:0]                        axi_aw_qos_o,
//    output [3:0]                        axi_aw_region_o,

    input                               axi_w_ready_i,                
    output                              axi_w_valid_o,
    output [AXI_DATA_WIDTH-1:0]         axi_w_data_o,
    output [AXI_STRB_WIDTH-1:0]         axi_w_strb_o,
    output                              axi_w_last_o,
//    output [AXI_USER_WIDTH-1:0]         axi_w_user_o,
    
    output                              axi_b_ready_o,                
    input                               axi_b_valid_i,
    input  [1:0]                        axi_b_resp_i,                 
    input  [AXI_ID_WIDTH-1:0]           axi_b_id_i,
//    input  [AXI_USER_WIDTH-1:0]         axi_b_user_i,

    input                               axi_ar_ready_i,                
    output                              axi_ar_valid_o,
    output [AXI_ADDR_WIDTH-1:0]         axi_ar_addr_o,
    output [AXI_ID_WIDTH-1:0]           axi_ar_id_o,
    output [7:0]                        axi_ar_len_o,
    output [2:0]                        axi_ar_size_o,
    output [1:0]                        axi_ar_burst_o,
//    output [2:0]                        axi_ar_prot_o,
//    output [AXI_USER_WIDTH-1:0]         axi_ar_user_o,
//    output                              axi_ar_lock_o,
//    output [3:0]                        axi_ar_cache_o,
//    output [3:0]                        axi_ar_qos_o,
//    output [3:0]                        axi_ar_region_o,
    
    input                               axi_r_valid_i,                
    input  [1:0]                        axi_r_resp_i,
    input  [AXI_DATA_WIDTH-1:0]         axi_r_data_i,
    input                               axi_r_last_i,
    input  [AXI_ID_WIDTH-1:0]           axi_r_id_i,
//    input  [AXI_USER_WIDTH-1:0]         axi_r_user_i,
    output                              axi_r_ready_o
);

    // handshake
    wire aw_hs      = axi_aw_ready_i & axi_aw_valid_o;
    wire w_hs       = axi_w_ready_i  & axi_w_valid_o;
    wire b_hs       = axi_b_ready_o  & axi_b_valid_i;
    wire ar_hs      = axi_ar_ready_i & axi_ar_valid_o;
    wire r_hs       = axi_r_ready_o  & axi_r_valid_i; 

    wire w_done     = w_hs & axi_w_last_o;// write done只是用于状态转换
    wire r_done     = r_hs & axi_r_last_i;

    // ------------------State Machine---------------------
    localparam [1:0] W_STATE_IDLE = 2'b00, W_STATE_ADDR = 2'b01, W_STATE_WRITE = 2'b10, W_STATE_RESP = 2'b11;
    localparam [1:0] R_STATE_IDLE = 2'b00, R_STATE_ADDR = 2'b01, R_STATE_READ  = 2'b10;
    reg r_ready, w_ready;
    reg [1:0] w_state, w_state_next, r_state, r_state_next;
    wire w_state_idle = w_state == W_STATE_IDLE, w_state_addr = w_state == W_STATE_ADDR, w_state_write = w_state == W_STATE_WRITE, w_state_resp = w_state == W_STATE_RESP;
    wire r_state_idle = r_state == R_STATE_IDLE, r_state_addr = r_state == R_STATE_ADDR, r_state_read  = r_state == R_STATE_READ;
    // 写通道状态切换
    ysyx_22040729_Reg #(2, W_STATE_IDLE) w_state_inst (clock, reset, w_state_next, w_state, w_valid_i & ~w_ready);
    assign w_state_next = ( {2{w_state_idle}}) & ( W_STATE_ADDR ) |
			              ( {2{w_state_addr}}) & ( aw_hs  ? W_STATE_WRITE: w_state ) |
			              ( {2{w_state_write}})& ( w_done ? W_STATE_RESP : w_state ) |
                          ( {2{w_state_resp}}) & ( b_hs   ? W_STATE_IDLE : w_state ) ;

    // 读通道状态切换
    ysyx_22040729_Reg #(2, R_STATE_IDLE) r_state_inst (clock, reset, r_state_next, r_state, r_valid_i & ~r_ready);
    assign r_state_next = ( {2{r_state_idle}}) & ( R_STATE_ADDR ) |
			              ( {2{r_state_addr}}) & ( ar_hs  ? R_STATE_READ : r_state ) |
			              ( {2{r_state_read}}) & ( r_done ? R_STATE_IDLE : r_state ) ;

    //
    ysyx_22040729_Reg #(1, 0) r_ready_inst (clock, reset, r_done, r_ready, r_done | r_ready);
    ysyx_22040729_Reg #(1, 0) w_ready_inst (clock, reset, b_hs  , w_ready, b_hs   | w_ready);
    assign r_ready_o = r_ready;
    assign w_ready_o = w_ready;

    // ------------------burst Transaction------------------
    localparam CNT_WID = (RW_DATA_WIDTH > AXI_DATA_WIDTH) ? $clog2($clog2(RW_DATA_WIDTH / AXI_DATA_WIDTH)+1) : 1;
    reg [CNT_WID-1:0] r_cnt;
    wire [7:0] r_len = ($clog2(AXI_DATA_WIDTH/8) < r_size_i) ? ((8'b1<<({29'b0,r_size_i}-$clog2(AXI_DATA_WIDTH/8)))-1) : 8'b0;
    wire [CNT_WID-1:0] r_cnt_next = r_state_addr ? {CNT_WID{1'b0}} : (r_cnt + 1);
    wire r_cnt_en = (r_hs & |r_len & r_state_read) | (r_state_addr);
    ysyx_22040729_Reg #(CNT_WID, {CNT_WID{1'b0}}) r_cnt_inst (clock, reset, r_cnt_next[CNT_WID-1:0], r_cnt, r_cnt_en);

    reg [CNT_WID-1:0] w_cnt;
    wire [7:0] w_len = ($clog2(AXI_DATA_WIDTH/8) < w_size_i) ? ((8'b1<<({29'b0,w_size_i}-$clog2(AXI_DATA_WIDTH/8)))-1) : 8'b0;
    wire [CNT_WID-1:0] w_cnt_next = w_state_addr ? {CNT_WID{1'b0}} : (w_cnt + 1);
    wire w_cnt_en = (w_hs & |w_len & w_state_write) | (w_state_addr);
    ysyx_22040729_Reg #(CNT_WID, {CNT_WID{1'b0}}) w_cnt_inst (clock, reset, w_cnt_next[CNT_WID-1:0], w_cnt, w_cnt_en);

    // ------------------Write Transaction------------------
    parameter AXI_SIZE      = $clog2(AXI_DATA_WIDTH / 8);
    wire [AXI_ID_WIDTH-1:0] axi_id              = {AXI_ID_WIDTH{1'b0}};
//    wire [AXI_USER_WIDTH-1:0] axi_user          = {AXI_USER_WIDTH{1'b0}};
    wire [2:0] axi_size     = AXI_SIZE[2:0];
    // Write address channel signals  以下没有备注初始化信号的都可能是你需要产生和用到的
    assign axi_aw_valid_o   = w_state_addr;
    assign axi_aw_addr_o    = w_addr_i;
    assign axi_aw_id_o      = axi_id;                                                                           //初始化信号即可
    assign axi_aw_len_o     = w_len;
    assign axi_aw_size_o    = |w_len ? axi_size : w_size_i;
    assign axi_aw_burst_o   = `ysyx_22040729_AXI_BURST_TYPE_INCR;                                                             
//    assign axi_aw_prot_o    = `ysyx_22040729_AXI_PROT_UNPRIVILEGED_ACCESS | `ysyx_22040729_AXI_PROT_SECURE_ACCESS | `ysyx_22040729_AXI_PROT_DATA_ACCESS;  //初始化信号即可
//    assign axi_aw_user_o    = axi_user;                                                                         //初始化信号即可
//    assign axi_aw_lock_o    = 1'b0;                                                                             //初始化信号即可
//    assign axi_aw_cache_o   = `ysyx_22040729_AXI_AWCACHE_WRITE_BACK_READ_AND_WRITE_ALLOCATE;                                  //初始化信号即可
//    assign axi_aw_qos_o     = 4'h0;                                                                             //初始化信号即可
//    assign axi_aw_region_o  = 4'h0;                                                                             //初始化信号即可

    // Write data channel signals
    generate if (RW_DATA_WIDTH > AXI_DATA_WIDTH) begin
        wire [AXI_DATA_WIDTH-1:0] axi_w_data_buf[(RW_DATA_WIDTH / AXI_DATA_WIDTH)];
        for (genvar i=0; i<(RW_DATA_WIDTH / AXI_DATA_WIDTH); i=i+1) begin
            assign axi_w_data_buf[i] = w_data_i[AXI_DATA_WIDTH*i + (AXI_DATA_WIDTH-1) : AXI_DATA_WIDTH*i];
        end
        assign axi_w_data_o = axi_w_data_buf[w_cnt];
    end else
        assign axi_w_data_o = w_data_i;
    endgenerate
    
    wire [AXI_STRB_WIDTH-1:0]         axi_w_strb_t;
    assign axi_w_strb_t[0] = 1'b1;
    generate
        for (genvar i=0; i<$clog2(AXI_STRB_WIDTH); i=i+1) begin
            assign axi_w_strb_t[(2**(i+1))-1 : 2**i] = |w_len ? {(2**i){1'b1}} : {(2**i){i<w_size_i}};
        end
    endgenerate
    assign axi_w_strb_o     = axi_w_strb_t << w_addr_i[$clog2(AXI_STRB_WIDTH)-1:0];
    assign axi_w_valid_o    = w_state_write;
    assign axi_w_last_o     = w_cnt==w_len[CNT_WID-1:0];
//    assign axi_w_user_o     = axi_user;                                                                         //初始化信号即可

    // Write back channel signals
    assign axi_b_ready_o    = w_state_resp;

    // ------------------Read Transaction------------------

    // Read address channel signals
    assign axi_ar_valid_o   = r_state_addr;
    assign axi_ar_addr_o    = r_addr_i;
    assign axi_ar_id_o      = axi_id;                                                                           //初始化信号即可                        
    assign axi_ar_len_o     = r_len;                                                                          
    assign axi_ar_size_o    = |r_len ? axi_size : r_size_i;
    assign axi_ar_burst_o   = `ysyx_22040729_AXI_BURST_TYPE_INCR;
//    assign axi_ar_prot_o    = `ysyx_22040729_AXI_PROT_UNPRIVILEGED_ACCESS | `ysyx_22040729_AXI_PROT_SECURE_ACCESS | `ysyx_22040729_AXI_PROT_DATA_ACCESS;  //初始化信号即可
//    assign axi_ar_user_o    = axi_user;                                                                         //初始化信号即可
//    assign axi_ar_lock_o    = 1'b0;                                                                             //初始化信号即可
//    assign axi_ar_cache_o   = `ysyx_22040729_AXI_ARCACHE_NORMAL_NON_CACHEABLE_NON_BUFFERABLE;                                 //初始化信号即可
//    assign axi_ar_qos_o     = 4'h0;                                                                             //初始化信号即可
//    assign axi_ar_region_o  = 4'h0;

    // Read data channel signals
    reg [RW_DATA_WIDTH-1:0] r_data_reg;
    assign axi_r_ready_o    = r_state_read;
    wire [RW_DATA_WIDTH-1:0] r_data_o_next;
    generate if (RW_DATA_WIDTH > AXI_DATA_WIDTH) begin
        for (genvar i=0; i<(RW_DATA_WIDTH / AXI_DATA_WIDTH); i=i+1) begin
            assign r_data_o_next[AXI_DATA_WIDTH*i + (AXI_DATA_WIDTH-1) : AXI_DATA_WIDTH*i] = 
            (r_cnt==i) ? axi_r_data_i : r_data_o[AXI_DATA_WIDTH*i + (AXI_DATA_WIDTH-1) : AXI_DATA_WIDTH*i];
        end
    end else
        assign r_data_o_next = axi_r_data_i;
    endgenerate
    ysyx_22040729_Reg #(RW_DATA_WIDTH, {RW_DATA_WIDTH{1'b0}}) data_read_o_inst (clock, reset, r_data_o_next, r_data_reg, r_hs);
    assign r_data_o = r_data_reg;

endmodule
module ysyx_22040729_Cache#(
    parameter RW_DATA_WIDTH     = 128,
    parameter AXI_ADDR_WIDTH    = 32,
    parameter RESET_INST = 32'h00000013
)(
    input  [31:0] i_addr_i,
    output [31:0] i_rdata_o,
    input         i_valid_i,
    output        i_ready_o,

    input  [31:0] d_addr_i,
    input         d_wen_i,
    input  [2 :0] d_size_i,
    input  [63:0] d_wdata_i,
    output [63:0] d_rdata_o,
    input         d_valid_i,
    output        d_ready_o,
    
    
    //cache<->memory
    //read
    output  [AXI_ADDR_WIDTH-1:0]         r_addr_o,
    output  [2:0]                        r_size_o,
	output                               r_valid_o, 
	input                                r_ready_i,  
    input   [RW_DATA_WIDTH-1:0]          r_data_i,
    //write
    output  [AXI_ADDR_WIDTH-1:0]         w_addr_o,
    output  [RW_DATA_WIDTH-1:0]          w_data_o,
    output  [2:0]                        w_size_o,
    output                               w_valid_o,  
	input                                w_ready_i,

    output[5:0]	    io_sram0_addr,
    output	        io_sram0_cen,
    output	        io_sram0_wen,
    output[127:0]	io_sram0_wmask,
    output[127:0]	io_sram0_wdata,
    input [127:0]	io_sram0_rdata,

    output[5:0]	    io_sram1_addr,
    output	        io_sram1_cen,
    output	        io_sram1_wen,
    output[127:0]	io_sram1_wmask,
    output[127:0]	io_sram1_wdata,
    input [127:0]	io_sram1_rdata,

    output[5:0]	    io_sram2_addr,
    output	        io_sram2_cen,
    output	        io_sram2_wen,
    output[127:0]	io_sram2_wmask,
    output[127:0]	io_sram2_wdata,
    input [127:0]	io_sram2_rdata,

    output[5:0]	    io_sram3_addr,
    output	        io_sram3_cen,
    output	        io_sram3_wen,
    output[127:0]	io_sram3_wmask,
    output[127:0]	io_sram3_wdata,
    input [127:0]	io_sram3_rdata,
    
    output[5:0]	    io_sram4_addr,
    output	        io_sram4_cen,
    output	        io_sram4_wen,
    output[127:0]	io_sram4_wmask,
    output[127:0]	io_sram4_wdata,
    input [127:0]	io_sram4_rdata,

    output[5:0]	    io_sram5_addr,
    output	        io_sram5_cen,
    output	        io_sram5_wen,
    output[127:0]	io_sram5_wmask,
    output[127:0]	io_sram5_wdata,
    input [127:0]	io_sram5_rdata,

    output[5:0]	    io_sram6_addr,
    output	        io_sram6_cen,
    output	        io_sram6_wen,
    output[127:0]	io_sram6_wmask,
    output[127:0]	io_sram6_wdata,
    input [127:0]	io_sram6_rdata,

    output[5:0]	    io_sram7_addr,
    output	        io_sram7_cen,
    output	        io_sram7_wen,
    output[127:0]	io_sram7_wmask,
    output[127:0]	io_sram7_wdata,
    input [127:0]	io_sram7_rdata,

    input fence_i,
    input clock,
    input reset
);
localparam IDLE=2'b11, CMPTAG=2'b00, ALLOC=2'b01, FENCE=2'b10;

// -------------- read ----------------

wire [AXI_ADDR_WIDTH-1:0] ir_addr;
wire [2:0]                ir_size;
wire                      ir_valid;
wire                      ir_ready;
wire [RW_DATA_WIDTH-1:0]  ir_data;

wire [AXI_ADDR_WIDTH-1:0] dr_addr;
wire [2:0]                dr_size;
wire                      dr_valid;
wire                      dr_ready;
wire [RW_DATA_WIDTH-1:0]  dr_data, dr_data_l;

wire ir_hs = ir_valid & ir_ready;
wire dr_hs = dr_valid & dr_ready;

wire arb_id, arb_id_next;//arbiter: icache first
ysyx_22040729_Reg #(1, 1'b0) arb_id_inst (clock, reset, arb_id_next, arb_id, ir_valid | dr_valid);
assign arb_id_next = (~ir_valid & dr_valid) | (ir_valid & dr_valid & arb_id & ~dr_ready);

assign r_addr_o  = arb_id ? dr_addr  : ir_addr ;
assign r_size_o  = arb_id ? dr_size  : ir_size ;
assign r_valid_o = arb_id ? dr_valid : ir_valid;
assign ir_ready  = arb_id ? 1'b0     : r_ready_i;
assign dr_ready  = arb_id ? r_ready_i: 1'b0;
assign ir_data   = r_data_i;
assign dr_data   = arb_id ? r_data_i : dr_data_l;
ysyx_22040729_Reg #(RW_DATA_WIDTH, {RW_DATA_WIDTH{1'b0}}) dr_data_l_inst (clock, reset, r_data_i, dr_data_l, dr_hs);


// -------------- write ---------------
wire [AXI_ADDR_WIDTH-1:0] dw_addr;
wire [2:0]                dw_size;
wire                      dw_valid;
wire                      dw_ready;
wire [RW_DATA_WIDTH-1:0]  dw_data;

wire dw_hs = dw_valid & dw_ready;

assign w_addr_o  = dw_addr;
assign w_data_o  = dw_data;
assign w_size_o  = dw_size;
assign w_valid_o = dw_valid;
assign dw_ready  = w_ready_i;

//--------------- icahce -------------- 2 * 256 * 64
localparam I_WAY = 2, I_LSIZE=32 , I_SET = 64, I_AXISIZE=$clog2(I_LSIZE);
wire icache_bypass_sel = i_addr_i[31:26]==6'h3f | i_addr_i[31]==1'b0;
wire icache_bypass = icache_bypass_sel;
reg  [1:0] istate, istate_next; //istate_prev;
reg  [I_SET-1:0] i_V[I_WAY-1:0];
reg  [I_SET-1:0] i_U;
reg  [20:0] i_tag[I_WAY-1:0][I_SET-1:0];
wire [I_WAY-1:0] icache_hit;

wire [20:0] icache_req_tag    = i_addr_i[31:11];
wire [5:0]  icache_req_index  = i_addr_i[10: 5];
wire [2:0]  icache_req_offset = i_addr_i[ 4: 2];

wire icache_req, icache_rdy, icache_rdy_d, ibypass_rdy, ibypass_rdy_d;
assign icache_req = i_valid_i & ~icache_bypass;
assign i_ready_o = icache_bypass ? ibypass_rdy : icache_rdy;
assign icache_rdy = (istate==CMPTAG) & (|icache_hit) & icache_req;
assign ibypass_rdy = ir_hs & icache_bypass;
ysyx_22040729_Reg #(1, 1'b0) icache_rdy_d_inst (clock, reset, icache_rdy, icache_rdy_d, 1);
ysyx_22040729_Reg #(1, 1'b0) ibypass_rdy_d_inst (clock, reset, ibypass_rdy, ibypass_rdy_d, 1);

generate for (genvar i=0; i<I_WAY; ++i) begin
    assign icache_hit[i] = i_V[i][icache_req_index] & (i_tag[i][icache_req_index] == icache_req_tag);
end endgenerate

//FSM
ysyx_22040729_Reg #(2, CMPTAG) icache_state_inst (clock, reset, istate_next, istate, 1'b1);
//ysyx_22040729_Reg #(2, CMPTAG) icache_state_prev_inst (clock, reset, istate, istate_prev, 1'b1);
assign istate_next = ( {2{istate == IDLE  }}) & ( CMPTAG ) |
			         ( {2{istate == CMPTAG}}) & ( icache_req & ~|icache_hit ? ALLOC : CMPTAG ) |
			         ( {2{istate == ALLOC }}) & ( ir_hs ? CMPTAG : ALLOC ) |
                     ( {2{istate == FENCE }}) & ( CMPTAG ) ;

//i_rdata_o
wire [2:0]  icache_req_offset_d;
ysyx_22040729_Reg #(3, 3'b0) icache_req_offset_stage_inst (clock, reset, icache_req_offset, icache_req_offset_d, icache_rdy);
wire icache_hit0_d;
ysyx_22040729_Reg #(1, {1{1'b0}}) icache_hit_stage_inst (clock, reset, icache_hit[0], icache_hit0_d, icache_rdy);
wire [31:0] icache_data_t[I_WAY-1:0];
wire [31:0] icache_data, i_rdata_d, i_rdata;
ysyx_22040729_Reg #(32, RESET_INST) i_rdata_stage_inst (clock, reset, i_rdata_o, i_rdata_d, ibypass_rdy_d | icache_rdy_d);
assign icache_data_t[0] = icache_req_offset_d[2] ? io_sram1_rdata[32*icache_req_offset_d[1:0] +: 32] : io_sram0_rdata[32*icache_req_offset_d[1:0] +: 32];
assign icache_data_t[1] = icache_req_offset_d[2] ? io_sram3_rdata[32*icache_req_offset_d[1:0] +: 32] : io_sram2_rdata[32*icache_req_offset_d[1:0] +: 32];
assign icache_data = icache_hit0_d ? icache_data_t[0] : icache_data_t[1];
assign i_rdata = ibypass_rdy_d ? r_data_i[31:0] : icache_data;
assign i_rdata_o = ibypass_rdy_d | icache_rdy_d ? i_rdata : i_rdata_d;

//i_V i_tag
wire [I_SET-1:0] ialloc_en[I_WAY-1:0];
generate for (genvar i=0; i<I_WAY; ++i) begin
    for (genvar j=0; j<I_SET; ++j) begin:i_V_tag_inst
        assign ialloc_en[i][j] = (istate==ALLOC) & ir_hs & (i!=i_U[icache_req_index]) & (j==icache_req_index);
        ysyx_22040729_Reg #(1, 1'b0) i_V_inst (clock, reset, 1'b1, i_V[i][j], ialloc_en[i][j]);
        ysyx_22040729_Reg #(21, 21'b0) i_tag_inst (clock, reset, icache_req_tag, i_tag[i][j], ialloc_en[i][j]);
    end
end endgenerate
//i_U
wire [I_SET-1:0] i_U_en;
wire i_U_next = icache_hit[0] ? 1'b0 : 1'b1;
generate for (genvar i=0; i<I_SET; ++i) begin:i_U_inst
    ysyx_22040729_Reg #(1, 1'b0) i_U_inst (clock, reset, i_U_next, i_U[i], i_U_en[i]);
    assign i_U_en[i] = (i==icache_req_index) & |icache_hit;
end endgenerate
//sram
assign io_sram0_addr  = icache_req_index;
assign io_sram0_cen   = 1'b0;
assign io_sram0_wen   = ~|ialloc_en[0];
assign io_sram0_wmask = 128'h0;
assign io_sram0_wdata = ir_data[127:0];

assign io_sram1_addr  = icache_req_index;
assign io_sram1_cen   = 1'b0;
assign io_sram1_wen   = ~|ialloc_en[0];
assign io_sram1_wmask = 128'h0;
assign io_sram1_wdata = ir_data[255:128];

assign io_sram2_addr  = icache_req_index;
assign io_sram2_cen   = 1'b0;
assign io_sram2_wen   = ~|ialloc_en[1];
assign io_sram2_wmask = 128'h0;
assign io_sram2_wdata = ir_data[127:0];

assign io_sram3_addr  = icache_req_index;
assign io_sram3_cen   = 1'b0;
assign io_sram3_wen   = ~|ialloc_en[1];
assign io_sram3_wmask = 128'h0;
assign io_sram3_wdata = ir_data[255:128];

//icache2mem
reg ir_valid_reg;
assign ir_addr  = {i_addr_i[31:5], icache_bypass ? i_addr_i[4:0] : 5'b0};
assign ir_size  = icache_bypass ? 3'd2 : I_AXISIZE[2:0];
assign ir_valid = ir_valid_reg;
wire ir_valid_set = ((istate==CMPTAG) & !(|icache_hit) & icache_req) | (icache_bypass & i_valid_i);
wire ir_valid_clr = (istate==ALLOC | icache_bypass) & (ir_ready);
ysyx_22040729_Reg #(1, 1'b0) ir_valid_inst (clock, reset, ir_valid_set, ir_valid_reg, ir_valid_set | ir_valid_clr);

//------------------------------------------------
//--------------- dcahce -------------- 2 * 256 * 64
localparam D_WAY = 2, D_LSIZE=32 , D_SET = 64, D_AXISIZE=$clog2(D_LSIZE);
wire dcache_bypass_sel = d_addr_i[31:26]==6'h3f | d_addr_i[31]==1'b0;
wire dcache_bypass = ~fence_i & dcache_bypass_sel;
reg  [1:0] dstate, dstate_next; ///dstate_prev;
reg  [D_SET-1:0] d_V[D_WAY-1:0];
reg  [D_SET-1:0] d_D[D_WAY-1:0];
reg  [D_SET-1:0] d_U;
reg  [20:0] d_tag[D_WAY-1:0][I_SET-1:0];
wire [D_WAY-1:0] dcache_hit;
wire dstate_idle   = (dstate==IDLE);
wire dstate_cmptag = (dstate==CMPTAG);
wire dstate_alloc  = (dstate==ALLOC);
wire dstate_fence  = (dstate==FENCE);

wire [20:0] dcache_req_tag    = d_addr_i[31:11];
wire [5:0]  dcache_req_index  = d_addr_i[10: 5];
wire [1:0]  dcache_req_offset = d_addr_i[ 4: 3];

wire dcache_req, dcache_rdy, dcache_rdy_d, dbypass_rdy, dbypass_rdy_d;
assign dcache_req = d_valid_i & ~dcache_bypass;
assign d_ready_o = fence_i ? dstate_idle : dcache_bypass ? dbypass_rdy : dcache_rdy;
assign dcache_rdy = dstate_cmptag & (|dcache_hit) & dcache_req;
assign dbypass_rdy = (d_wen_i ? dw_hs : dr_hs) & dcache_bypass;
ysyx_22040729_Reg #(1, 1'b0) dcache_rdy_d_inst (clock, reset, dcache_rdy&~d_wen_i, dcache_rdy_d, 1);
ysyx_22040729_Reg #(1, 1'b0) bypass_rdy_d_inst (clock, reset, dbypass_rdy&~d_wen_i, dbypass_rdy_d, 1);
//

generate for (genvar i=0; i<D_WAY; ++i) begin
    assign dcache_hit[i] = d_V[i][dcache_req_index] & (d_tag[i][dcache_req_index] == dcache_req_tag);
end endgenerate

//fence
wire [$clog2(D_WAY*D_SET)-1:0] fence_cnt;
wire dw_valid_fence_set = dstate_fence & d_D[fence_cnt[$clog2(D_WAY)-1:0]][fence_cnt[$clog2(D_WAY*D_SET)-1:$clog2(D_WAY)]];
wire fence_cnt_incr = dstate_fence & (dw_hs | ~dw_valid_fence_set);
ysyx_22040729_Reg #($clog2(D_WAY*D_SET), {$clog2(D_WAY*D_SET){1'b0}}) fence_cnt_inst (clock, reset, fence_cnt + 1, fence_cnt, fence_cnt_incr);
wire fence_done = (fence_cnt=='1) & fence_cnt_incr;
//FSM
ysyx_22040729_Reg #(2, CMPTAG) dcache_state_inst (clock, reset, dstate_next, dstate, 1'b1);
//ysyx_22040729_Reg #(2, CMPTAG) dcache_state_prev_inst (clock, reset, dstate, dstate_prev, 1'b1);
wire dalloc_done = (dr_hs|~dr_valid) & (dw_hs|~dw_valid);
assign dstate_next = ( {2{dstate_idle  }}) & ( fence_i ? IDLE : CMPTAG  ) |
			         ( {2{dstate_cmptag}}) & ( fence_i ? FENCE : dcache_req & ~|dcache_hit ? ALLOC : CMPTAG ) |
			         ( {2{dstate_alloc }}) & ( dalloc_done ? CMPTAG : ALLOC ) |
                     ( {2{dstate_fence }}) & ( fence_done ? IDLE : FENCE );

//
wire [2:0] d_size_d, dcache_req_bias_d;
wire [1:0] dcache_req_offset_d;
wire dcache_hit0_d;
wire [63:0] dcache_data_t[D_WAY-1:0];
wire [63:0] dcache_data, d_rdata_d, d_rdata_t, d_rdata/*verilator split_var*/;
ysyx_22040729_Reg #(3, 3'b0) d_size_stage_inst (clock, reset, d_size_i, d_size_d, (dcache_rdy|dbypass_rdy)&~d_wen_i);
ysyx_22040729_Reg #(3, 3'b0) dcache_req_bias_stage_inst (clock, reset, d_addr_i[2:0], dcache_req_bias_d, (dcache_rdy|dbypass_rdy)&~d_wen_i);
ysyx_22040729_Reg #(2, 2'b0) dcache_req_offset_stage_inst (clock, reset, dcache_req_offset, dcache_req_offset_d, dcache_rdy&~d_wen_i);
ysyx_22040729_Reg #(1, {1{1'b0}}) dcache_hit_stage_inst (clock, reset, dcache_hit[0], dcache_hit0_d, dcache_rdy&~d_wen_i);
ysyx_22040729_Reg #(64, {64{1'b0}}) d_rdata_stage_inst (clock, reset, d_rdata_o, d_rdata_d, dbypass_rdy_d | dcache_rdy_d);
assign dcache_data_t[0] = dcache_req_offset_d[1] ? io_sram5_rdata[64*dcache_req_offset_d[0] +: 64] : io_sram4_rdata[64*dcache_req_offset_d[0] +: 64];
assign dcache_data_t[1] = dcache_req_offset_d[1] ? io_sram7_rdata[64*dcache_req_offset_d[0] +: 64] : io_sram6_rdata[64*dcache_req_offset_d[0] +: 64];
assign dcache_data = dcache_hit0_d ? dcache_data_t[0] : dcache_data_t[1];
assign d_rdata_t = dbypass_rdy_d ? r_data_i[63:0] : dcache_data;

assign d_rdata[7:0]   = d_rdata_t[8*dcache_req_bias_d[2:0] +: 8];
assign d_rdata[15: 8] = d_size_d[1:0]==2'b00 ? d_size_d[2] ? '0 : { 8{d_rdata[ 7]}} : d_rdata_t[(8+(16*dcache_req_bias_d[2:1])) +: 8];
assign d_rdata[31:16] = d_size_d[1]  ==1'b0  ? d_size_d[2] ? '0 : {16{d_rdata[15]}} : d_rdata_t[(16+(32*dcache_req_bias_d[2])) +: 16];
assign d_rdata[63:32] = d_size_d[1:0]!=2'b11 ? d_size_d[2] ? '0 : {32{d_rdata[31]}} : d_rdata_t[63:32];

assign d_rdata_o = dbypass_rdy_d | dcache_rdy_d ? d_rdata : d_rdata_d;


//d_V d_tag
wire [D_SET-1:0] dalloc_en[D_WAY-1:0];
generate for (genvar i=0; i<D_WAY; ++i) begin
    for (genvar j=0; j<D_SET; ++j) begin:d_V_tag_inst
        assign dalloc_en[i][j] = (dstate_alloc) & dalloc_done & (i!=d_U[dcache_req_index]) & (j==dcache_req_index);
        ysyx_22040729_Reg #(1, 1'b0) d_V_inst (clock, reset, 1'b1, d_V[i][j], dalloc_en[i][j]);
        ysyx_22040729_Reg #(21, 21'b0) d_tag_inst (clock, reset, dcache_req_tag, d_tag[i][j], dalloc_en[i][j]);
    end
end endgenerate
//d_U
wire [I_SET-1:0] d_U_en;
wire d_U_next = dcache_hit[0] ? 1'b0 : 1'b1;
generate for (genvar i=0; i<I_SET; ++i) begin:d_U_inst
    ysyx_22040729_Reg #(1, 1'b0) d_U_inst (clock, reset, d_U_next, d_U[i], d_U_en[i]);
    assign d_U_en[i] = (i==dcache_req_index) & |dcache_hit;
end endgenerate
//d_D
wire [D_SET-1:0] ddirty_set[D_WAY-1:0];
generate for (genvar i=0; i<D_WAY; ++i) begin
    for (genvar j=0; j<D_SET; ++j) begin:d_D_inst
        assign ddirty_set[i][j] = (dstate_cmptag) & d_wen_i & (dcache_hit[i]) & (j==dcache_req_index);
        ysyx_22040729_Reg #(1, 1'b0) d_D_inst (clock, reset, ddirty_set[i][j], d_D[i][j], dalloc_en[i][j] | ddirty_set[i][j] | dstate_idle);
    end
end endgenerate


//sram
wire [63:0] sram_wmask_t = ({64{d_size_i[1:0]==2'b00}} & 64'hFF)|
                           ({64{d_size_i[1:0]==2'b01}} & 64'hFFFF)|
                           ({64{d_size_i[1:0]==2'b10}} & 64'hFFFFFFFF)|
                           ({64{d_size_i[1:0]==2'b11}} & 64'hFFFFFFFFFFFFFFFF);
wire [63:0] d_wdata_skew = d_wdata_i << ({ d_addr_i[2:0], 3'b0 });
wire [127:0] sram_wdata = {d_wdata_skew, d_wdata_skew};
wire [127:0] sram_wmask = {64'b0, sram_wmask_t} << ({ d_addr_i[3:0], 3'b0 });

assign io_sram4_addr  = dstate_fence ? fence_cnt[$clog2(D_WAY*D_SET)-1:$clog2(D_WAY)] : dcache_req_index;
assign io_sram4_cen   = 1'b0;
assign io_sram4_wen   = ~(|dalloc_en[0] | (dcache_hit[0] & ~dcache_req_offset[1] & d_wen_i));
assign io_sram4_wmask = |dalloc_en[0] ? 128'h0 : ~sram_wmask;
assign io_sram4_wdata = |dalloc_en[0] ? dr_data[127:0] : sram_wdata;

assign io_sram5_addr  = dstate_fence ? fence_cnt[$clog2(D_WAY*D_SET)-1:$clog2(D_WAY)] : dcache_req_index;
assign io_sram5_cen   = 1'b0;
assign io_sram5_wen   = ~(|dalloc_en[0] | (dcache_hit[0] & dcache_req_offset[1] & d_wen_i));
assign io_sram5_wmask = |dalloc_en[0] ? 128'h0 : ~sram_wmask;
assign io_sram5_wdata = |dalloc_en[0] ? dr_data[255:128] : sram_wdata;

assign io_sram6_addr  = dstate_fence ? fence_cnt[$clog2(D_WAY*D_SET)-1:$clog2(D_WAY)] : dcache_req_index;
assign io_sram6_cen   = 1'b0;
assign io_sram6_wen   = ~(|dalloc_en[1] | (dcache_hit[1] & ~dcache_req_offset[1] & d_wen_i));
assign io_sram6_wmask = |dalloc_en[1] ? 128'h0 : ~sram_wmask;
assign io_sram6_wdata = |dalloc_en[1] ? dr_data[127:0] : sram_wdata;

assign io_sram7_addr  = dstate_fence ? fence_cnt[$clog2(D_WAY*D_SET)-1:$clog2(D_WAY)] : dcache_req_index;
assign io_sram7_cen   = 1'b0;
assign io_sram7_wen   = ~(|dalloc_en[1] | (dcache_hit[1] & dcache_req_offset[1] & d_wen_i));
assign io_sram7_wmask = |dalloc_en[1] ? 128'h0 : ~sram_wmask;
assign io_sram7_wdata = |dalloc_en[1] ? dr_data[255:128] : sram_wdata;

//dcache2mem
///read
reg dr_valid_reg;
assign dr_addr  = {d_addr_i[31:5], dcache_bypass ? d_addr_i[4:0] : 5'b0};
assign dr_size  = dcache_bypass ? {1'b0, d_size_i[1:0]} : D_AXISIZE[2:0];
assign dr_valid = dr_valid_reg;
wire dr_valid_set = ((dstate_cmptag) & !(|dcache_hit) & dcache_req) | (dcache_bypass & d_valid_i & ~d_wen_i);
wire dr_valid_clr = (dstate_alloc | dcache_bypass) & (dr_ready);
ysyx_22040729_Reg #(1, 1'b0) dr_valid_inst (clock, reset, ~dr_valid_clr, dr_valid_reg, dr_valid_set | dr_valid_clr);
///write
reg dw_valid_reg;
assign dw_addr  = dstate_fence  ? {d_tag[fence_cnt[$clog2(D_WAY)-1:0]][fence_cnt[$clog2(D_WAY*D_SET)-1:$clog2(D_WAY)]],
                                   fence_cnt[$clog2(D_WAY*D_SET)-1:$clog2(D_WAY)], 5'b0} :
                  dcache_bypass ? d_addr_i[31:0] :
                  {d_tag[~d_U[dcache_req_index]][dcache_req_index], dcache_req_index, 5'b0};
assign dw_size  = dr_size;
assign dw_data  = dstate_fence  ? fence_cnt[0]? {io_sram7_rdata, io_sram6_rdata} : {io_sram5_rdata, io_sram4_rdata} :
                  dcache_bypass ? {{RW_DATA_WIDTH-64{1'b0}}, d_wdata_skew} :
                  d_U[dcache_req_index] ? {io_sram5_rdata, io_sram4_rdata} : {io_sram7_rdata, io_sram6_rdata};
assign dw_valid = dw_valid_reg;
wire dw_valid_set = ((dstate_alloc ) & d_D[~d_U[dcache_req_index]][dcache_req_index]) |
                    (dcache_bypass & d_valid_i & d_wen_i) | dw_valid_fence_set;
wire dw_valid_clr = (dstate_fence | dstate_alloc | dcache_bypass ) & (dw_ready);
ysyx_22040729_Reg #(1, 1'b0) dw_valid_inst (clock, reset, ~dw_valid_clr, dw_valid_reg, dw_valid_set | dw_valid_clr);


endmodule
module ysyx_22040729_CLINT #(TICK_COUNT = 'h2, DATA_WIDTH = 64, ADDR_WIDTH=16)(
    input  [ADDR_WIDTH-1:0] clint_addr,
    input  [DATA_WIDTH-1:0] clint_wdata,
    output [DATA_WIDTH-1:0] clint_rdata,
    input                   clint_wen,
    input                   clint_sel,
    input  [2:0]            clint_size,

    //output clint_sip,
    output clint_tirq,

    input  clock,
    input  reset
);

//read data
wire [DATA_WIDTH-1:0] clint_rdata_next_t, clint_rdata_next/*verilator split_var*/;
assign clint_rdata_next_t = ({DATA_WIDTH{clint_mtimecmp_sel}} &  clint_mtimecmp) |
                            ({DATA_WIDTH{clint_mtime_sel   }} &  clint_mtime   ) ;
assign clint_rdata_next[7:0]   = clint_rdata_next_t[8*clint_addr[2:0] +: 8];
assign clint_rdata_next[15: 8] = clint_size[1:0]==2'b00 ? clint_size[2] ? '0 : { 8{clint_rdata_next[ 7]}} : clint_rdata_next_t[(8+(16*clint_addr[2:1])) +: 8];
assign clint_rdata_next[31:16] = clint_size[1]  ==1'b0  ? clint_size[2] ? '0 : {16{clint_rdata_next[15]}} : clint_rdata_next_t[(16+(32*clint_addr[2])) +: 16];
assign clint_rdata_next[63:32] = clint_size[1:0]!=2'b11 ? clint_size[2] ? '0 : {32{clint_rdata_next[31]}} : clint_rdata_next_t[63:32];
ysyx_22040729_Reg #(DATA_WIDTH, {DATA_WIDTH{1'b0}}) clint_rdata_inst (clock, reset, clint_rdata_next, clint_rdata, clint_sel&~clint_wen);

///timer
wire [11:0] clint_mtimer_next, clint_mtimer;
ysyx_22040729_Reg #(12, 12'h0) CLINT_mtimer (clock, reset, clint_mtimer_next, clint_mtimer, 1);
assign clint_mtimer_next = (clint_mtimer>=TICK_COUNT) ? 12'b0 : clint_mtimer+1;
///
wire [DATA_WIDTH-1:0] clint_mtime_next, clint_mtime, clint_mtime_hwdata;//mtime:0xbff8
wire clint_mtime_wen, clint_mtime_hwen, clint_mtime_sel;
ysyx_22040729_Reg #(DATA_WIDTH, 64'h0) CLINT_mtime (clock, reset, clint_mtime_next, clint_mtime, clint_mtime_wen);
assign clint_mtime_next = clint_mtime_hwen ? clint_mtime_hwdata : clint_wdata;
assign clint_mtime_sel = clint_sel & clint_addr[15:3]=={12'hbff, 1'b1};
assign clint_mtime_wen = (clint_mtime_sel & clint_wen) | clint_mtime_hwen;
assign clint_mtime_hwdata = clint_mtime + 1;
assign clint_mtime_hwen = clint_mtimer>=TICK_COUNT;

wire [DATA_WIDTH-1:0] clint_mtimecmp_next, clint_mtimecmp;//mtimecmp:0x4000
wire clint_mtimecmp_wen, clint_mtimecmp_sel;
ysyx_22040729_Reg #(DATA_WIDTH, 64'h0) CLINT_mtimecmp (clock, reset, clint_mtimecmp_next, clint_mtimecmp, clint_mtimecmp_wen);
assign clint_mtimecmp_next = clint_wdata;
assign clint_mtimecmp_sel = clint_sel & clint_addr[15:3]=={12'h400, 1'b0};
assign clint_mtimecmp_wen = clint_mtimecmp_sel & clint_wen;
    

//irq
assign clint_tirq = clint_mtime >= clint_mtimecmp;


endmodule
module ysyx_22040729_CPU #(
    parameter DATA_WIDTH = 64,
    parameter ADDR_WIDTH = 32,
    parameter INST_WIDTH = 32,
    parameter REG_ADDR_W = 5,
    parameter RESET_ADDR = 64'h80000000,
    parameter RESET_INST = 32'h00000013
)(
  input  clock,
  input  reset,
  output fence_o,

  output                      mem_valid,
  input                       mem_ready,
  input   [DATA_WIDTH-1:0]    mem_data_read,
  output  [DATA_WIDTH-1:0]    mem_data_write,
  output  [ADDR_WIDTH-1:0]    mem_addr,
  output  [2:0]               mem_size,
  output                      mem_wen,

  output                      if_valid,
  input                       if_ready,
  input   [INST_WIDTH-1:0]    if_data_read,
  output  [ADDR_WIDTH-1:0]    if_addr
);

wire flow_if, flow_id, flow_exe, flow_mem, flow_wb;
wire flush_if, flush_id, flush_exe, flush_mem; //flush_wb;
wire stall_if, stall_id, stall_exe, stall_mem, stall_wb;
wire if_hs  = if_valid & if_ready;
wire mem_hs = mem_valid & mem_ready;

wire alu_busy;
//wire if_hs_d, mem_hs_d;
//ysyx_22040729_Reg #(1, 1'b0) if_hs_d_inst (clock, reset, if_hs, if_hs_d, 1);
//ysyx_22040729_Reg #(1, 1'b0) mem_hs_d_inst (clock, reset, mem_hs, mem_hs_d, 1);
wire flow   = (if_hs | ~if_valid) & (mem_hs | ~mem_valid) & (~fence_o | mem_ready) & !alu_busy;
wire mem_hazard_id, mem_hazard_exe;

assign flow_if   = flow & ~stall_if;
assign flow_id   = flow & ~stall_id;
assign flow_exe  = flow & ~stall_exe;
assign flow_mem  = flow & ~stall_mem;
assign flow_wb   = flow & ~stall_wb;
assign stall_if  = mem_hazard_exe | mem_hazard_id;
assign stall_id  = mem_hazard_exe | mem_hazard_id;
assign stall_exe = mem_hazard_exe;
assign stall_mem = 0;
assign stall_wb  = 0;
//--------------------IF-------------------------
wire boot;
wire [INST_WIDTH-1:0] instruction, instruction_load;
wire [DATA_WIDTH-1:0] pc, pc_next, pc_id;

ysyx_22040729_Reg #(1, 1'b1) if_valid_inst (clock, reset, flow_if, if_valid, flow_if | if_ready);
assign if_addr = pc[ADDR_WIDTH-1:0];
ysyx_22040729_Reg #(1, 0) boot_inst (clock, reset, 1, boot, flow_if);
ysyx_22040729_Reg #(DATA_WIDTH, RESET_ADDR) PC_inst (clock, reset, flush_if ? pc_next : pc+4, pc, flow_if);

assign instruction = boot ? if_data_read : RESET_INST;
ysyx_22040729_Reg #(INST_WIDTH, RESET_INST) instruction_load_inst (clock, reset, instruction, instruction_load, if_hs);

//-------------------------IF2ID---------------------------------------
assign flush_if = !(pc_next==pc | flush_id | ~boot) | system_jump;
assign instruction_id = flush_id ? RESET_INST : if_hs ? instruction : instruction_load;
ysyx_22040729_Reg #(1, 1'b0) flush_id_stage_inst (clock, reset, flush_if, flush_id, flow_id);
ysyx_22040729_Reg #(DATA_WIDTH, {DATA_WIDTH{1'b0}}) PC_stage_inst (clock, reset, pc, pc_id, flow_id);

//--------------------ID---------------------------
wire rf_we_exe, mem_wen_exe, alu_src2_ri_exe, alu_len_dw_exe;
wire rf_we_id, mem_wen_id, alu_src2_ri_id, alu_len_dw_id;
wire [2:0] rf_wdata_src_exe, rf_wdata_src_id;
wire [REG_ADDR_W-1:0] rf_waddr_exe, rf_waddr_id;
wire [INST_WIDTH-1:0] instruction_id, instruction_exe;
wire [DATA_WIDTH-1:0] immediate_exe, immediate_id, pc_exe;
wire [DATA_WIDTH-1:0] rf_rdata1_exe, rf_rdata2_exe, rf_rdata1_id, rf_rdata2_id;

wire rf_we_wb;
wire [REG_ADDR_W-1:0] rf_waddr_wb;
wire [DATA_WIDTH-1:0] rf_wdata_wb;
wire [DATA_WIDTH-1:0] npc;

wire ecall, mret, csr_enable;
wire system_jump;
wire [DATA_WIDTH-1:0] system_jump_entry;
ysyx_22040729_IDU #(
  .DATA_WIDTH(DATA_WIDTH),
  .ADDR_WIDTH(DATA_WIDTH),
  .INST_WIDTH(INST_WIDTH),
  .REG_ADDR_W(REG_ADDR_W)
) IDU_inst (
  .clock                  (clock),
  .reset                  (reset),

  .instruction_i          (instruction_id),
  .pc_i                   (pc_id),
  .system_jump_i          (system_jump),
  .system_jump_entry_i    (system_jump_entry),
  .rf_we_i                (rf_we_wb),
  .rf_waddr_i             (rf_waddr_wb),
  .rf_wdata_i             (rf_wdata_wb),

  .rf_we_exe_i            (rf_we_exe),
  .rf_we_mem_i            (rf_we_mem),
  .rf_wdata_src_exe_i     (rf_wdata_src_exe),
  .rf_wdata_src_mem_i     (rf_wdata_src_mem),
  .dst_addr_exe_i         (rf_waddr_exe),
  .dst_addr_mem_i         (rf_waddr_mem),
  .ALU_result_exe_i       (ALU_result_exe),
  .immediate_exe_i        (immediate_exe),
  .pc_exe_i               (pc_exe),
  .ALU_result_mem_i       (ALU_result_mem),
  .immediate_mem_i        (immediate_mem),
  .pc_mem_i               (pc_mem),

  .mem_hazard_o           (mem_hazard_id),

  .rf_we_o                (rf_we_id),
  .rf_waddr_o             (rf_waddr_id),
  .rf_rdata1_o            (rf_rdata1_id),
  .rf_rdata2_o            (rf_rdata2_id),
  .mem_wen_o              (mem_wen_id),
  .alu_src2_ri_o          (alu_src2_ri_id),
  .alu_len_dw_o           (alu_len_dw_id),
  .rf_wdata_src_o         (rf_wdata_src_id),
  .immediate_o            (immediate_id),
  .ecall_o                (ecall),
  .mret_o                 (mret),
  .csr_enable_o           (csr_enable),
  .npc                    (npc),
  .pc_next_o              (pc_next)
);
//Exception
wire exception, ext_irq, tmr_irq, epc_select;
wire [DATA_WIDTH-1:0] excp_mcause;
ysyx_22040729_Excp Excp_inst(
  .ext_irq      (ext_irq),
  .tmr_irq      (tmr_irq),
  .ecall        (ecall),
  .excp_mcause  (excp_mcause),
  .epc_select   (epc_select),
  .exception    (exception)
);
wire [2:0] csr_wfunc;
wire clint_tirq;
wire [DATA_WIDTH-1:0] csr_rdata_id, csr_rdata_exe, csr_mtvec_vis, csr_mepc_hwdata, csr_mcause_hwdata, csr_mepc_vis;
ysyx_22040729_CSR CSR_inst(
  .csr_addr           (instruction_id[31:20]),
  .csr_wfunc          (csr_wfunc),
  .csr_uimm           (instruction_id[19:15]),
  .csr_wsrc           (rf_rdata1_id),
  .csr_rdata          (csr_rdata_id),
  .csr_mtvec_vis      (csr_mtvec_vis),
  .csr_mepc_vis       (csr_mepc_vis),
  .csr_mepc_hwdata    (csr_mepc_hwdata),
  .csr_mcause_hwdata  (csr_mcause_hwdata),
  .exception          (exception),
  .mret               (mret),
  .eirp_i             (0),
  .tirp_i             (clint_tirq),
  .eirp_o             (ext_irq),
  .tirp_o             (tmr_irq),
  .flow_i             (flow_id),
  .clock              (clock),
  .reset              (reset)
);
assign system_jump_entry =({DATA_WIDTH{exception}} & csr_mtvec_vis) |
                          ({DATA_WIDTH{mret     }} & csr_mepc_vis ) |
                          ({DATA_WIDTH{!(mret | exception)}} & RESET_ADDR);
assign csr_wfunc = instruction_id[14:12] & {3{csr_enable}};
assign csr_mepc_hwdata = epc_select ? flush_id ? pc : npc : pc_id;
assign csr_mcause_hwdata = excp_mcause;
assign system_jump = exception | mret;

//---------------------------ID2EXE-------------------------------
ysyx_22040729_Reg #(1, 1'b0) flush_exe_stage_inst (clock, reset, flush_id | mem_hazard_id, flush_exe, flow_exe);
ysyx_22040729_Reg #(1, 1'b0) rf_we_exe_stage_inst (clock, reset, mem_hazard_id?1'b0:rf_we_id, rf_we_exe, flow_exe);
ysyx_22040729_Reg #(1, 1'b0) mem_wen_exe_stage_inst (clock, reset, mem_hazard_id?1'b0:mem_wen_id, mem_wen_exe, flow_exe);
ysyx_22040729_Reg #(1, 1'b0) alu_src2_ri_exe_stage_inst (clock, reset, alu_src2_ri_id, alu_src2_ri_exe, flow_exe);
ysyx_22040729_Reg #(1, 1'b0) alu_len_dw_exe_stage_inst (clock, reset, alu_len_dw_id, alu_len_dw_exe, flow_exe);
ysyx_22040729_Reg #(3, 3'b0) rf_wdata_src_exe_stage_inst (clock, reset, mem_hazard_id?3'b0:rf_wdata_src_id, rf_wdata_src_exe, flow_exe);
ysyx_22040729_Reg #(REG_ADDR_W, {REG_ADDR_W{1'b0}}) rf_waddr_exe_stage_inst (clock, reset, rf_waddr_id, rf_waddr_exe, flow_exe);
ysyx_22040729_Reg #(INST_WIDTH, RESET_INST) instruction_exe_stage_inst (clock, reset, instruction_id, instruction_exe, flow_exe);
ysyx_22040729_Reg #(DATA_WIDTH, {DATA_WIDTH{1'b0}}) rf_rdata1_exe_stage_inst (clock, reset, rf_rdata1_id, rf_rdata1_exe, flow_exe);
ysyx_22040729_Reg #(DATA_WIDTH, {DATA_WIDTH{1'b0}}) rf_rdata2_exe_stage_inst (clock, reset, rf_rdata2_id, rf_rdata2_exe, flow_exe);
ysyx_22040729_Reg #(DATA_WIDTH, {DATA_WIDTH{1'b0}}) csr_rdata_exe_stage_inst (clock, reset, csr_rdata_id, csr_rdata_exe, flow_exe);
ysyx_22040729_Reg #(DATA_WIDTH, {DATA_WIDTH{1'b0}}) immediate_exe_stage_inst (clock, reset, immediate_id, immediate_exe, flow_exe);
ysyx_22040729_Reg #(DATA_WIDTH, {DATA_WIDTH{1'b0}}) pc_exe_stage_inst (clock, reset, pc_id, pc_exe, flow_exe);


//-------------------------------EXE----------------------------
wire rf_we_mem, mem_wen_mem;
wire [2:0] rf_wdata_src_mem;
wire [REG_ADDR_W-1:0] rf_waddr_mem;
wire [INST_WIDTH-1:0] instruction_mem;
wire [DATA_WIDTH-1:0] mem_wdata_exe, mem_wdata_mem, pc_mem, immediate_mem;
wire [DATA_WIDTH-1:0] ALU_result_mem, ALU_result_exe;
ysyx_22040729_EXE #(
  .DATA_WIDTH(DATA_WIDTH),
  .INST_WIDTH(INST_WIDTH),
  .REG_ADDR_W(REG_ADDR_W)
) EXE_inst(
  .clock               (clock),
  .reset               (reset),
  .exe_flow            (flow_exe),
  .rf_rdata1_i         (rf_rdata1_exe),
  .rf_rdata2_i         (rf_rdata2_exe),
  .alu_src2_ri_i       (alu_src2_ri_exe),
  .alu_len_dw_i        (alu_len_dw_exe),
  .immediate_i         (immediate_exe),
  .instruction_i       (instruction_exe),
  .csr_rdata_i         (csr_rdata_exe),
  .rf_we_wb_i          (rf_we_wb        ),
  .rf_we_mem_i         (rf_we_mem       ),
  .rf_wdata_src_mem_i  (rf_wdata_src_mem),
  .dst_addr_wb_i       (rf_waddr_wb     ),
  .dst_addr_mem_i      (rf_waddr_mem    ),
  .rf_wdata_wb_i       (rf_wdata_wb     ),

  .alu_busy            (alu_busy),
  .mem_hazard_o        (mem_hazard_exe),
  .mem_wdata_exe_o     (mem_wdata_exe),
  .ALU_result_o        (ALU_result_exe)
);


//----------------------------EXE2MEM-----------------------
ysyx_22040729_Reg #(1, 1'b0) flush_mem_stage_inst (clock, reset, flush_exe|mem_hazard_exe, flush_mem, flow_mem);
ysyx_22040729_Reg #(1, 1'b0) rf_we_mem_stage_inst (clock, reset, mem_hazard_exe?1'b0:rf_we_exe, rf_we_mem, flow_mem);
ysyx_22040729_Reg #(1, 1'b0) mem_wen_mem_stage_inst (clock, reset, mem_hazard_exe?1'b0:mem_wen_exe, mem_wen_mem, flow_mem);
ysyx_22040729_Reg #(3, 3'b0) rf_wdata_src_mem_stage_inst (clock, reset, mem_hazard_exe?3'b0:rf_wdata_src_exe, rf_wdata_src_mem, flow_mem);
ysyx_22040729_Reg #(REG_ADDR_W, {REG_ADDR_W{1'b0}}) rf_waddr_mem_stage_inst (clock, reset, rf_waddr_exe, rf_waddr_mem, flow_mem);
ysyx_22040729_Reg #(DATA_WIDTH, {DATA_WIDTH{1'b0}}) ALU_result_mem_stage_inst (clock, reset, ALU_result_exe, ALU_result_mem, flow_mem);
ysyx_22040729_Reg #(DATA_WIDTH, {DATA_WIDTH{1'b0}}) mem_wdata_mem_stage_inst (clock, reset, mem_wdata_exe, mem_wdata_mem, flow_mem);
ysyx_22040729_Reg #(DATA_WIDTH, {DATA_WIDTH{1'b0}}) immediate_mem_stage_inst (clock, reset, immediate_exe, immediate_mem, flow_mem);
ysyx_22040729_Reg #(DATA_WIDTH, {DATA_WIDTH{1'b0}}) pc_mem_stage_inst (clock, reset, pc_exe, pc_mem, flow_mem);
ysyx_22040729_Reg #(INST_WIDTH, {INST_WIDTH{1'b0}}) instruction_mem_stage_inst (clock, reset, instruction_exe, instruction_mem, flow_mem);


//----------------------------MEM----------------------------------
wire [2:0] rf_wdata_src_wb;
wire [DATA_WIDTH-1:0] pc_wb, immediate_wb, ALU_result_wb, mem_rdata_clint, mem_rdata_wb/*verilator split_var*/;

wire mem_wdata_forward = (|instruction_mem[24:20]) & (instruction_mem[24:20]==rf_waddr_wb ) & rf_we_wb;
wire mem_addr_forward  = (|instruction_mem[19:15]) & (instruction_mem[19:15]==rf_waddr_wb ) & rf_we_wb;

wire clint_sel, clint_sel_wb;

wire mem_valid_set, mem_valid_clr, mem_valid_reg;
ysyx_22040729_Reg #(1, 1'b0) mem_valid_inst (clock, reset, mem_valid_set, mem_valid_reg, mem_valid_set | mem_valid_clr);
assign mem_valid_set  = ((rf_wdata_src_exe==3'b001) | mem_wen_exe) & flow_mem;
assign mem_valid_clr  = mem_ready | clint_sel;
assign mem_valid      = mem_valid_reg & ~clint_sel;
assign mem_data_write = mem_wdata_forward ? rf_wdata_wb : mem_wdata_mem; //forward
assign mem_addr       = (mem_addr_forward ? rf_wdata_wb[31:0] : ALU_result_mem[31:0]) + immediate_mem[31:0];
assign mem_wen        = mem_wen_mem;
assign mem_size       = instruction_mem[14:12];

assign fence_o = {instruction_mem[14:12], instruction_mem[6:0]} == 10'b0010001111;

//clint
ysyx_22040729_CLINT CLINT_inst(
  .clint_addr  (mem_addr[15:0]),
  .clint_wdata (mem_data_write),
  .clint_rdata (mem_rdata_clint),
  .clint_wen   (mem_wen),
  .clint_sel   (clint_sel),
  .clint_size  (mem_size),
  
  .clint_tirq  (clint_tirq),

  .clock       (clock),
  .reset       (reset)
);
assign clint_sel = mem_addr[ADDR_WIDTH-1:16]==16'h0200;

//---------------------------MEM2WB--------------------------------
//wire [INST_WIDTH-1:0] instruction_wb;
//wire [2:0] mem_addr_wb;
//ysyx_22040729_Reg #(3, 3'b0) mem_addr_wb_stage_inst (clock, reset, mem_addr[2:0], mem_addr_wb, flow_wb);
ysyx_22040729_Reg #(1, 1'b0) clint_sel_wb_stage_inst (clock, reset, clint_sel, clint_sel_wb, flow_wb);
assign mem_rdata_wb = clint_sel_wb ? mem_rdata_clint : mem_data_read;
//ysyx_22040729_Reg #(1, 1'b0) flush_wb_stage_inst (clock, reset, flush_mem, flush_wb, flow_wb);
ysyx_22040729_Reg #(1, 1'b0) rf_we_wb_stage_inst (clock, reset, rf_we_mem, rf_we_wb, flow_wb);
ysyx_22040729_Reg #(3, 3'b0) rf_wdata_src_wb_stage_inst (clock, reset, rf_wdata_src_mem, rf_wdata_src_wb, flow_wb);
ysyx_22040729_Reg #(REG_ADDR_W, {REG_ADDR_W{1'b0}}) rf_waddr_wb_stage_inst (clock, reset, rf_waddr_mem, rf_waddr_wb, flow_wb);
//ysyx_22040729_Reg #(INST_WIDTH, {INST_WIDTH{1'b0}}) instruction_wb_stage_inst (clock, reset, instruction_mem, instruction_wb, flow_wb);
ysyx_22040729_Reg #(DATA_WIDTH, {DATA_WIDTH{1'b0}}) ALU_result_wb_stage_inst (clock, reset, ALU_result_mem, ALU_result_wb, flow_wb);
ysyx_22040729_Reg #(DATA_WIDTH, {DATA_WIDTH{1'b0}}) immediate_wb_stage_inst (clock, reset, immediate_mem, immediate_wb, flow_wb);
ysyx_22040729_Reg #(DATA_WIDTH, {DATA_WIDTH{1'b0}}) pc_wb_stage_inst (clock, reset, pc_mem, pc_wb, flow_wb);

//----------------------------WB-------------------------------------
wire exec_once;
wire [DATA_WIDTH-1:0] rf_wdata_wb, rf_wdata_wb_t, rf_wdata_wb_load;
assign rf_wdata_wb_t = ({DATA_WIDTH{rf_wdata_src_wb == 3'b000}} & (ALU_result_wb  )) |
                       ({DATA_WIDTH{rf_wdata_src_wb == 3'b001}} & (mem_rdata_wb   )) |
                       ({DATA_WIDTH{rf_wdata_src_wb == 3'b010}} & (immediate_wb   )) |
                       ({DATA_WIDTH{rf_wdata_src_wb == 3'b100}} & (pc_wb + immediate_wb)) |
                       ({DATA_WIDTH{rf_wdata_src_wb == 3'b101}} & (pc_wb + 64'd4  )) ;
ysyx_22040729_Reg #(DATA_WIDTH, {DATA_WIDTH{1'b0}}) rf_wdata_wb_load_inst (clock, reset, rf_wdata_wb_t, rf_wdata_wb_load, exec_once);
assign rf_wdata_wb = exec_once ? rf_wdata_wb_t : rf_wdata_wb_load;

//------------------------------------------------------------------
ysyx_22040729_Reg #(1, 1'b0) exec_once_inst (clock, reset, flow_wb&~flush_mem, exec_once, 1);



endmodule
module ysyx_22040729_CSR #(DATA_WIDTH = 64)(
    input  [11:0] csr_addr,
    input  [2:0]  csr_wfunc,
    input  [4:0]  csr_uimm,
    input  [DATA_WIDTH-1:0] csr_wsrc,
    output [DATA_WIDTH-1:0] csr_rdata,

    output [DATA_WIDTH-1:0] csr_mtvec_vis,
    output [DATA_WIDTH-1:0] csr_mepc_vis,
    input  [DATA_WIDTH-1:0] csr_mepc_hwdata,
    input  [DATA_WIDTH-1:0] csr_mcause_hwdata,

    input  exception,
    input  mret,

    input  eirp_i,
    input  tirp_i,
    output eirp_o,
    output tirp_o,

    input  flow_i,
    input  clock,
    input  reset
);

//write data
wire [DATA_WIDTH-1:0] csr_wdata, csr_wdata_temp;
assign csr_wdata_temp = csr_wfunc[2] ? {{DATA_WIDTH-5{1'b0}}, csr_uimm} : csr_wsrc;
assign csr_wdata  = ({DATA_WIDTH{csr_wfunc[1:0]==2'b01}} & ( csr_wdata_temp            )) |
                    ({DATA_WIDTH{csr_wfunc[1:0]==2'b10}} & ( csr_wdata_temp | csr_rdata)) |
                    ({DATA_WIDTH{csr_wfunc[1:0]==2'b11}} & (~csr_wdata_temp & csr_rdata)) ;
////
//read data
assign csr_rdata =  ({DATA_WIDTH{csr_mstatus_sel}} &  csr_mstatus) |
                    ({DATA_WIDTH{csr_mie_sel    }} &  csr_mie    ) |
                    ({DATA_WIDTH{csr_mtvec_sel  }} &  csr_mtvec  ) |
                    ({DATA_WIDTH{csr_mepc_sel   }} &  csr_mepc   ) |
                    ({DATA_WIDTH{csr_mcause_sel }} &  csr_mcause ) |
                    ({DATA_WIDTH{csr_mip_sel    }} &  csr_mip    ) ;
////


wire [DATA_WIDTH-1:0] csr_mstatus;//mstatus:0x300
wire csr_mstatus_sel = csr_addr==12'h300;

wire csr_mstatus_mie, csr_mstatus_mie_next, csr_mstatus_mie_hwdata; // mie
wire csr_mstatus_mie_wen, csr_mstatus_mie_hwwen;
ysyx_22040729_Reg #(1, 1'b0) CSR_mstatus_mie (clock, reset, csr_mstatus_mie_next, csr_mstatus_mie, csr_mstatus_mie_wen);
assign csr_mstatus_mie_next = csr_mstatus_mie_hwwen ? csr_mstatus_mie_hwdata : csr_wdata[3];
assign csr_mstatus_mie_hwdata = mret ? csr_mstatus_mpie : 0;
assign csr_mstatus_mie_wen = (csr_mstatus_sel & |csr_wfunc[1:0]) | csr_mstatus_mie_hwwen;
assign csr_mstatus_mie_hwwen = (exception | mret) & flow_i;

wire csr_mstatus_mpie, csr_mstatus_mpie_next, csr_mstatus_mpie_hwdata; // mpie
wire csr_mstatus_mpie_wen, csr_mstatus_mpie_hwwen;
ysyx_22040729_Reg #(1, 1'b0) CSR_mstatus_mpie (clock, reset, csr_mstatus_mpie_next, csr_mstatus_mpie, csr_mstatus_mpie_wen);
assign csr_mstatus_mpie_next = csr_mstatus_mpie_hwwen ? csr_mstatus_mpie_hwdata : csr_wdata[7];
assign csr_mstatus_mpie_hwdata = csr_mstatus_mie & flow_i;
assign csr_mstatus_mpie_wen = (csr_mstatus_sel & |csr_wfunc[1:0]) | csr_mstatus_mpie_hwwen;
assign csr_mstatus_mpie_hwwen = exception;

assign csr_mstatus = {28'h0, 2'b10, 2'b10, 19'b0, 2'b11, 3'b0, csr_mstatus_mpie, 3'b0, csr_mstatus_mie, 3'b0};


wire [DATA_WIDTH-1:0] csr_mie_next, csr_mie;//mie:0x304
wire csr_mie_wen, csr_mie_sel;
wire csr_mie_meie, csr_mie_mtie;
ysyx_22040729_Reg #(1, 1'b0) CSR_mie_meie (clock, reset, csr_mie_next[11], csr_mie_meie, csr_mie_wen);
ysyx_22040729_Reg #(1, 1'b0) CSR_mie_mtie (clock, reset, csr_mie_next[ 7], csr_mie_mtie, csr_mie_wen);
assign csr_mie = {52'b0, csr_mie_meie, 3'b0, csr_mie_mtie, 7'b0};
assign csr_mie_next = csr_wdata;
assign csr_mie_sel = csr_addr==12'h304;
assign csr_mie_wen = csr_mie_sel & |csr_wfunc[1:0];
assign eirp_o = csr_mstatus_mie & csr_mie_meie & eirp_i;
assign tirp_o = csr_mstatus_mie & csr_mie_mtie & tirp_i;

wire [DATA_WIDTH-1:0] csr_mtvec_next, csr_mtvec;//mtvec:0x305
wire csr_mtvec_wen, csr_mtvec_sel;
ysyx_22040729_Reg #(DATA_WIDTH, {DATA_WIDTH{1'b0}}) CSR_mtvec (clock, reset, csr_mtvec_next, csr_mtvec, csr_mtvec_wen);
assign csr_mtvec_next = csr_wdata;
assign csr_mtvec_sel = csr_addr==12'h305;
assign csr_mtvec_wen = csr_mtvec_sel & |csr_wfunc[1:0];
assign csr_mtvec_vis = csr_mtvec;

wire [DATA_WIDTH-1:0] csr_mepc_next, csr_mepc;//mepc:0x341
wire csr_mepc_wen, csr_mepc_wen_hw, csr_mepc_sel;
ysyx_22040729_Reg #(DATA_WIDTH, {DATA_WIDTH{1'b0}}) CSR_mepc (clock, reset, csr_mepc_next, csr_mepc, csr_mepc_wen);
assign csr_mepc_next = csr_mepc_wen_hw ? csr_mepc_hwdata : csr_wdata;
assign csr_mepc_sel = csr_addr==12'h341;
assign csr_mepc_wen = (csr_mepc_sel & |csr_wfunc[1:0]) | csr_mepc_wen_hw;
assign csr_mepc_wen_hw = exception;
assign csr_mepc_vis = csr_mepc;

wire [DATA_WIDTH-1:0] csr_mcause_next, csr_mcause;//mcause:0x342
wire csr_mcause_wen, csr_mcause_wen_hw, csr_mcause_sel;
ysyx_22040729_Reg #(DATA_WIDTH, {DATA_WIDTH{1'b0}}) CSR_mcause (clock, reset, csr_mcause_next, csr_mcause, csr_mcause_wen);
assign csr_mcause_next = csr_mcause_wen_hw ? csr_mcause_hwdata : csr_wdata;
assign csr_mcause_sel = csr_addr==12'h342;
assign csr_mcause_wen = (csr_mcause_sel & |csr_wfunc[1:0]) | csr_mcause_wen_hw;
assign csr_mcause_wen_hw = exception;

wire [DATA_WIDTH-1:0] csr_mip;//mip:0x344
wire csr_mip_sel;
wire csr_mip_meip, csr_mip_mtip;
ysyx_22040729_Reg #(1, 1'b0) CSR_mip_meip (clock, reset, eirp_i, csr_mip_meip, 1'b1);
ysyx_22040729_Reg #(1, 1'b0) CSR_mip_mtip (clock, reset, tirp_i, csr_mip_mtip, 1'b1);
assign csr_mip = {52'b0, csr_mip_meip, 3'b0, csr_mip_mtip, 7'b0};
assign csr_mip_sel = csr_addr==12'h344;
    
endmodule
module ysyx_22040729_Excp #(DATA_WIDTH = 64)(
    input  ext_irq,
    input  tmr_irq,
    input  ecall,

    output [DATA_WIDTH-1:0]excp_mcause,
    output epc_select,

    output exception
);

wire interrupt = ext_irq | tmr_irq;
wire [3:0] itrpt_cause, error_cause;

assign exception = ext_irq | tmr_irq | ecall;

assign epc_select = interrupt;

assign excp_mcause[DATA_WIDTH-1] = interrupt;
assign excp_mcause[DATA_WIDTH-2:4] = {DATA_WIDTH-5{1'b0}};
assign excp_mcause[3:0] = interrupt ? itrpt_cause : error_cause;
assign itrpt_cause = ext_irq ? 4'hb :
                     tmr_irq ? 4'h7 :
                     4'h0;
assign error_cause = 4'hb;
    
endmodule
module ysyx_22040729_IDU #(
    parameter DATA_WIDTH = 64,
    parameter ADDR_WIDTH = 64,
    parameter INST_WIDTH = 32,
    parameter REG_ADDR_W = 5
)(
  input  clock,
  input  reset,

  input  [INST_WIDTH-1:0] instruction_i,
  input  [ADDR_WIDTH-1:0] pc_i,

  input  system_jump_i,
  input  [ADDR_WIDTH-1:0] system_jump_entry_i,
  input  rf_we_i,
  input  [REG_ADDR_W-1:0] rf_waddr_i,
  input  [DATA_WIDTH-1:0] rf_wdata_i,

  input                   rf_we_exe_i,
  input                   rf_we_mem_i,
  input  [2:0]            rf_wdata_src_exe_i,
  input  [2:0]            rf_wdata_src_mem_i,
  input  [REG_ADDR_W-1:0] dst_addr_exe_i,
  input  [REG_ADDR_W-1:0] dst_addr_mem_i,
  input  [DATA_WIDTH-1:0] ALU_result_exe_i,
  input  [DATA_WIDTH-1:0] immediate_exe_i,
  input  [DATA_WIDTH-1:0] pc_exe_i,
  input  [DATA_WIDTH-1:0] ALU_result_mem_i,
  input  [DATA_WIDTH-1:0] immediate_mem_i,
  input  [DATA_WIDTH-1:0] pc_mem_i,
  
  output                  mem_hazard_o,

  output rf_we_o,
  output [REG_ADDR_W-1:0] rf_waddr_o,
  output [DATA_WIDTH-1:0] rf_rdata1_o,
  output [DATA_WIDTH-1:0] rf_rdata2_o,
  output mem_wen_o,
  output alu_src2_ri_o,
  output alu_len_dw_o,
  output ecall_o,
  output mret_o,
  output csr_enable_o,
  output [2:0] rf_wdata_src_o,
  output [DATA_WIDTH-1:0] immediate_o,
  output [ADDR_WIDTH-1:0] npc,
  output [ADDR_WIDTH-1:0] pc_next_o
);

//Decoder
wire [1:0] npc_src;
ysyx_22040729_IDU_Decoder #(32, 64) Decoder_inst(
  .instruction  (instruction_i),
  .ecall        (ecall_o),
  .mret         (mret_o),
  .csr_enable   (csr_enable_o),
  .rf_we        (rf_we_o),
  .rf_wdata_src (rf_wdata_src_o),
  .npc_src      (npc_src),
  .alu_len_dw   (alu_len_dw_o),
  .mem_wen      (mem_wen_o),
  .alu_src2_ri  (alu_src2_ri_o),
  .immediate    (immediate_o)
);


//RegFile
wire [REG_ADDR_W-1:0] rf_raddr1, rf_raddr2;
wire [DATA_WIDTH-1:0] rf_rdata1, rf_rdata2;
ysyx_22040729_IDU_RegisterFile #(32, DATA_WIDTH) RF_inst (
  .clock    (clock),
  .reset    (reset),
  .wen      (rf_we_i),
  .waddr    (rf_waddr_i),
  .wdata    (rf_wdata_i),
  .raddr1   (rf_raddr1),
  .rdata1   (rf_rdata1),
  .raddr2   (rf_raddr2),
  .rdata2   (rf_rdata2)
);
assign rf_raddr1  = instruction_i[19:15];
assign rf_raddr2  = instruction_i[24:20];
assign rf_waddr_o = instruction_i[11:7];

//forward
wire                  rf_we_exe    = rf_we_exe_i;
wire                  rf_we_mem    = rf_we_mem_i;
wire [REG_ADDR_W-1:0] dst_addr_exe = dst_addr_exe_i;
wire [REG_ADDR_W-1:0] dst_addr_mem = dst_addr_mem_i;
wire [DATA_WIDTH-1:0] rf_wdata_exe = ({DATA_WIDTH{rf_wdata_src_exe_i == 3'b000}} & (ALU_result_exe_i  )) |
                                     ({DATA_WIDTH{rf_wdata_src_exe_i == 3'b010}} & (immediate_exe_i   )) |
                                     ({DATA_WIDTH{rf_wdata_src_exe_i == 3'b100}} & (pc_exe_i + immediate_exe_i)) |
                                     ({DATA_WIDTH{rf_wdata_src_exe_i == 3'b101}} & (pc_exe_i + 64'd4  ));
wire [DATA_WIDTH-1:0] rf_wdata_mem = ({DATA_WIDTH{rf_wdata_src_mem_i == 3'b000}} & (ALU_result_mem_i  )) |
                                     ({DATA_WIDTH{rf_wdata_src_mem_i == 3'b010}} & (immediate_mem_i   )) |
                                     ({DATA_WIDTH{rf_wdata_src_mem_i == 3'b100}} & (pc_mem_i + immediate_mem_i)) |
                                     ({DATA_WIDTH{rf_wdata_src_mem_i == 3'b101}} & (pc_mem_i + 64'd4  ));
wire src1_forward_exe = (|rf_raddr1) & (rf_raddr1==dst_addr_exe) & rf_we_exe;
wire src1_forward_mem = (|rf_raddr1) & (rf_raddr1==dst_addr_mem) & rf_we_mem;
wire src2_forward_exe = (|rf_raddr2) & (rf_raddr2==dst_addr_exe) & rf_we_exe;
wire src2_forward_mem = (|rf_raddr2) & (rf_raddr2==dst_addr_mem) & rf_we_mem;

assign rf_rdata1_o = src1_forward_exe ? rf_wdata_exe : src1_forward_mem ? rf_wdata_mem : rf_rdata1;
assign rf_rdata2_o = src2_forward_exe ? rf_wdata_exe : src2_forward_mem ? rf_wdata_mem : rf_rdata2;


assign mem_hazard_o = (rf_wdata_src_mem_i==3'b001 | rf_wdata_src_exe_i==3'b001) &
                      (npc_src[1] | (csr_enable_o&~instruction_i[14])) & //branch or csrw
                      (src1_forward_mem | src2_forward_mem | src1_forward_exe | src2_forward_exe);

//npc
wire [DATA_WIDTH-1:0] snpc, dnpc, rnpc, bnpc;
wire branch_switch;
wire [DATA_WIDTH:0] sub_result = rf_rdata1_o - rf_rdata2_o;
MuxKey #(6, 3, 1) mux_branch (
  branch_switch,
  instruction_i[14:12], {
    3'b000, !(|sub_result),              //beq 
    3'b001, |sub_result,                 //bne
    3'b100, sub_result[DATA_WIDTH-1],    //blt
    3'b101, !sub_result[DATA_WIDTH-1],   //bge
    3'b110, sub_result[DATA_WIDTH],      //bltu
    3'b111, !sub_result[DATA_WIDTH]}     //bgeu
);
assign snpc = pc_i + 4;
assign dnpc = pc_i + immediate_o;
assign rnpc = rf_rdata1_o + immediate_o;
assign bnpc = branch_switch ? dnpc : snpc;
assign pc_next_o =  system_jump_i ? system_jump_entry_i : npc;
assign npc =  ({DATA_WIDTH{npc_src == 2'b00}} & snpc) |
              ({DATA_WIDTH{npc_src == 2'b01}} & dnpc) |
              ({DATA_WIDTH{npc_src == 2'b10}} & rnpc) |
              ({DATA_WIDTH{npc_src == 2'b11}} & bnpc) ;


endmodule
/*========================================================
#
# Author: Steven
#
# QQ : 935438447 
#
# Last modified:	2022-04-20 20:49
#
# Filename:		ysyx_22040729_RegisterFile.v
#
# Description: RegisterFile
#
=========================================================*/
module ysyx_22040729_IDU_RegisterFile #(REGI_DEPTH = 32, DATA_WIDTH = 64) (
  input  clock,
  input  reset,
  input  wen,
  input  [$clog2(REGI_DEPTH)-1:0] waddr,
  input  [$clog2(REGI_DEPTH)-1:0] raddr1,
  input  [$clog2(REGI_DEPTH)-1:0] raddr2,
  input  [DATA_WIDTH-1:0] wdata,
  output [DATA_WIDTH-1:0] rdata1,
  output [DATA_WIDTH-1:0] rdata2
);
reg [DATA_WIDTH-1:0] rf [REGI_DEPTH-1:0];

assign rdata1 = reset ? '0 : raddr1=='0 ? '0 : (wen & raddr1==waddr) ? wdata : rf[raddr1];

assign rdata2 = reset ? '0 : raddr2=='0 ? '0 : (wen & raddr2==waddr) ? wdata : rf[raddr2];

always @(posedge clock) begin
  if (wen&!reset) rf[waddr] <= waddr=='0 ? '0 : wdata;
end
endmodule
/*========================================================
#
# Author: Steven
#
# QQ : 935438447 
#
# Last modified: 2022-04-21 22:16
#
# Filename: ysyx_22040729_Decoder.v
#
# Description: 
#
=========================================================*/
module ysyx_22040729_IDU_Decoder #(INST_WIDTH = 32, DATA_WIDTH = 64) (
  input  [INST_WIDTH-1:0] instruction,

  output ecall,
  output mret,
  output csr_enable,

  output rf_we,  
  output [2:0] rf_wdata_src,
  output [1:0] npc_src,
  output alu_len_dw,
  output alu_src2_ri,
  output mem_wen,
  output [DATA_WIDTH-1:0] immediate
);

//localparam NONE_TYPE = 3'd0;
localparam R_TYPE    = 3'd1;
localparam I_TYPE    = 3'd2;
localparam S_TYPE    = 3'd3;
localparam B_TYPE    = 3'd4;
localparam U_TYPE    = 3'd5;
localparam J_TYPE    = 3'd6;
localparam SYS_TYPE  = 3'd7;

wire [6:0] opcode;
assign opcode = instruction[6:0];

wire [2:0] inst_type;

assign ecall = instruction==32'h00000073;
assign mret  = instruction==32'h30200073;
assign csr_enable = inst_type==SYS_TYPE;

MuxKey #(12, 7, 9) opcode_decode (
  {rf_wdata_src, npc_src, alu_len_dw, inst_type},
  opcode[6:0], {
  7'b0110111, 3'b010, 2'b00, 1'b0, U_TYPE,     //LUI
  7'b0010111, 3'b100, 2'b00, 1'b0, U_TYPE,     //AUIPC
  7'b1101111, 3'b101, 2'b01, 1'b0, J_TYPE,     //JAL
  7'b1100111, 3'b101, 2'b10, 1'b0, I_TYPE,     //JALR
  7'b1100011, 3'b000, 2'b11, 1'b0, B_TYPE,     //BEQ
  7'b0000011, 3'b001, 2'b00, 1'b0, I_TYPE,     //LB
  7'b0100011, 3'b000, 2'b00, 1'b0, S_TYPE,     //SB
  7'b0010011, 3'b000, 2'b00, 1'b0, I_TYPE,     //ADDI
  7'b0110011, 3'b000, 2'b00, 1'b0, R_TYPE,     //ADD
  7'b0011011, 3'b000, 2'b00, 1'b1, I_TYPE,     //ADDIW
  7'b0111011, 3'b000, 2'b00, 1'b1, R_TYPE,     //ADDW
  7'b1110011, 3'b000, 2'b00, 1'b0, SYS_TYPE}   //SYSTEM
);

MuxKey #(7, 3, 3) inst_type_decode (
  {rf_we, mem_wen, alu_src2_ri},
  inst_type, {
  R_TYPE,   1'b1, 1'b0, 1'b0,
  I_TYPE,   1'b1, 1'b0, 1'b1,
  S_TYPE,   1'b0, 1'b1, 1'b1,
  B_TYPE,   1'b0, 1'b0, 1'b0,
  U_TYPE,   1'b1, 1'b0, 1'b0,
  J_TYPE,   1'b1, 1'b0, 1'b0,
  SYS_TYPE, 1'b1, 1'b0, 1'b1}
);

assign immediate[63:31] = {33{instruction[31]}};
assign immediate[30:20] = inst_type==U_TYPE ? instruction[30:20] : {11{instruction[31]}};
assign immediate[19:12] = (inst_type==U_TYPE || inst_type==J_TYPE) ? instruction[19:12] : {8{instruction[31]}};
assign immediate[11:11] = (inst_type==I_TYPE || inst_type==S_TYPE) ? instruction[31] :
                          (inst_type==J_TYPE) ? instruction[20] :
                          (inst_type==B_TYPE) ? instruction[7] : 1'b0;
assign immediate[10: 5] = (inst_type==I_TYPE || inst_type==S_TYPE || inst_type==B_TYPE || inst_type==J_TYPE) ? instruction[30:25] : 6'b0;
assign immediate[ 4: 1] = (inst_type==I_TYPE || inst_type==J_TYPE) ? instruction[24:21] : (inst_type==S_TYPE || inst_type==B_TYPE) ? instruction[11:8] : 4'b0;
assign immediate[ 0: 0] = inst_type==I_TYPE ? instruction[20] : inst_type==S_TYPE ? instruction[7] : 1'b0;




endmodule
module ysyx_22040729_EXE #(
    parameter DATA_WIDTH = 64,
    parameter INST_WIDTH = 32,
    parameter REG_ADDR_W = 5
)(
  input  clock,
  input  reset,

  input  exe_flow,

  input  [DATA_WIDTH-1:0] rf_rdata1_i,
  input  [DATA_WIDTH-1:0] rf_rdata2_i,
  input  alu_src2_ri_i,
  input  alu_len_dw_i,
  input  [DATA_WIDTH-1:0] immediate_i,
  input  [INST_WIDTH-1:0] instruction_i,
  input  [DATA_WIDTH-1:0] csr_rdata_i,
  input                   rf_we_wb_i,
  input                   rf_we_mem_i,
  input  [2:0]            rf_wdata_src_mem_i,
  input  [REG_ADDR_W-1:0] dst_addr_wb_i,
  input  [REG_ADDR_W-1:0] dst_addr_mem_i,
  input  [DATA_WIDTH-1:0] rf_wdata_wb_i,
  //input  [DATA_WIDTH-1:0] ALU_result_mem_i,
  //input  [DATA_WIDTH-1:0] immediate_mem_i,
  //input  [DATA_WIDTH-1:0] pc_mem_i,

  output                  alu_busy,

  output                  mem_hazard_o,
  output [DATA_WIDTH-1:0] mem_wdata_exe_o,
  output [DATA_WIDTH-1:0] ALU_result_o
);
wire mem_cmd = {instruction_i[6], instruction_i[4:2]}==4'b0;
wire csr_cmd = instruction_i[6:2]==5'b11100;
wire std_cmd = !(mem_cmd | csr_cmd);

//forward
wire [REG_ADDR_W-1:0] src1_addr    = instruction_i[19:15];
wire [REG_ADDR_W-1:0] src2_addr    = instruction_i[24:20];
wire                  rf_we_wb     = rf_we_wb_i;
wire                  rf_we_mem    = rf_we_mem_i;
wire [REG_ADDR_W-1:0] dst_addr_wb  = dst_addr_wb_i;
wire [REG_ADDR_W-1:0] dst_addr_mem = dst_addr_mem_i;
wire [DATA_WIDTH-1:0] rf_wdata_wb  = rf_wdata_wb_i;
// wire [DATA_WIDTH-1:0] rf_wdata_mem = ({DATA_WIDTH{rf_wdata_src_mem_i == 3'b000}} & (ALU_result_mem_i  )) |
//                                      ({DATA_WIDTH{rf_wdata_src_mem_i == 3'b010}} & (immediate_mem_i   )) |
//                                      ({DATA_WIDTH{rf_wdata_src_mem_i == 3'b100}} & (pc_mem_i + immediate_mem_i)) |
//                                      ({DATA_WIDTH{rf_wdata_src_mem_i == 3'b101}} & (pc_mem_i + 64'd4  ));
wire src1_forward_wb  = (|src1_addr) & (src1_addr==dst_addr_wb ) & rf_we_wb ;
wire src1_forward_mem = (|src1_addr) & (src1_addr==dst_addr_mem) & rf_we_mem;
wire src2_forward_wb  = (|src2_addr) & (src2_addr==dst_addr_wb ) & rf_we_wb ;
wire src2_forward_mem = (|src2_addr) & (src2_addr==dst_addr_mem) & rf_we_mem;
wire src1_forward_wbed, src2_forward_wbed;
wire [DATA_WIDTH-1:0] rf_wdata_wbed;
ysyx_22040729_Reg #(1, 1'b0) src1_forward_wbed_inst (clock, reset, mem_hazard_o&src1_forward_wb, src1_forward_wbed, 1);
ysyx_22040729_Reg #(1, 1'b0) src2_forward_wbed_inst (clock, reset, mem_hazard_o&src2_forward_wb, src2_forward_wbed, 1);
ysyx_22040729_Reg #(DATA_WIDTH, {DATA_WIDTH{1'b0}}) rf_wdata_wbed_inst (clock, reset, rf_wdata_wb, rf_wdata_wbed, mem_hazard_o&(src1_forward_wb|src2_forward_wb));

assign mem_wdata_exe_o = src2_forward_wb ? rf_wdata_wb : rf_rdata2_i;

assign mem_hazard_o = (rf_wdata_src_mem_i == 3'b001) & (src1_forward_mem|src2_forward_mem) & ~mem_cmd;

//ALU
wire [DATA_WIDTH-1:0] ALU_src1, ALU_src2, ALU_result;
wire [2:0] alu_func3 = instruction_i[14:12];
wire [6:0] alu_func7 = instruction_i[31:25];
ysyx_22040729_EXE_ALU #(DATA_WIDTH) ALU_inst (
  .clock        (clock),
	.reset        (reset),
  .exe_flow     (exe_flow),
  .src1         (ALU_src1),
  .src2         (ALU_src2),
  .alu_func3    (alu_func3),
  .alu_func7    (alu_func7),
  .alu_src2_ri  (alu_src2_ri_i),
  .alu_len_dw   (alu_len_dw_i),
  .alu_busy     (alu_busy),
  .result       (ALU_result)
);
assign ALU_src1 = src1_forward_mem ? rf_rdata1_i :
                  src1_forward_wb ? rf_wdata_wb : 
                  src1_forward_wbed ? rf_wdata_wbed : rf_rdata1_i;
assign ALU_src2 = alu_src2_ri_i ? immediate_i : 
                  src2_forward_mem ? rf_rdata2_i :
                  src2_forward_wb ? rf_wdata_wb :
                  src2_forward_wbed ? rf_wdata_wbed : rf_rdata2_i;
assign ALU_result_o = ({DATA_WIDTH{std_cmd}} & (ALU_result )) |
                      ({DATA_WIDTH{mem_cmd}} & (ALU_src1   )) |
                      ({DATA_WIDTH{csr_cmd}} & (csr_rdata_i));

endmodule
/*========================================================
#
# Author: Steven
#
# QQ : 935438447 
#
# Last modified: 2022-04-21 22:23
#
# Filename: ysyx_22040729_ALU.v
#
# Description: 
#
=========================================================*/
module ysyx_22040729_EXE_ALU #(DATA_WIDTH = 64)(
  input  clock,
  input  reset,
  input  exe_flow,
  input  [DATA_WIDTH-1:0] src1,
  input  [DATA_WIDTH-1:0] src2,
  input  [2:0] alu_func3,
  input  [6:0] alu_func7,
  input  alu_src2_ri,
  input  alu_len_dw,

  output alu_busy,
  output [DATA_WIDTH-1:0] result
);
wire [DATA_WIDTH-1:0] result_before_dw;
assign result = alu_len_dw ? {{33{result_before_dw[31]}}, result_before_dw[30:0]} : result_before_dw;

wire [DATA_WIDTH-1:0] result_rbasic, result_ibasic;
assign result_before_dw = alu_src2_ri ? result_ibasic : result_rbasic;

//add
wire [DATA_WIDTH:0] add_result;
assign add_result = src1 + src2;

//sub
wire [DATA_WIDTH:0] sub_result;
assign sub_result = src1 - src2;

//sll
wire [DATA_WIDTH-1:0] sll_result;
assign sll_result = src1 << src2[5:0];

//slt
wire [DATA_WIDTH-1:0] slt_result;
assign slt_result = {{DATA_WIDTH-1{1'b0}}, sub_result[DATA_WIDTH-1]};

//sltu
wire [DATA_WIDTH-1:0] sltu_result;
assign sltu_result = {{DATA_WIDTH-1{1'b0}}, sub_result[DATA_WIDTH]};

//xor
wire [DATA_WIDTH-1:0] xor_result;
assign xor_result = src1 ^ src2;

//srl(a)
wire [DATA_WIDTH-1:0] srla_result, srl_result, sra_result, srl_result_t, srlw_result_t, sra_result_t, sraw_result_t, eff_mask, eff_mask_w;
wire [5:0] shift_amount = {alu_len_dw ? 1'b0 : src2[5], src2[4:0]};
assign eff_mask = {DATA_WIDTH{1'b1}} >> shift_amount;
assign eff_mask_w = {{DATA_WIDTH/2{1'b0}}, eff_mask[DATA_WIDTH-1:DATA_WIDTH/2]};
assign srl_result_t = src1 >> shift_amount;
assign srlw_result_t = srl_result_t & eff_mask_w;
assign sra_result_t = (srl_result_t & eff_mask) | ({DATA_WIDTH{src1[DATA_WIDTH-1]}} & (~eff_mask));
assign sraw_result_t = (srl_result_t & eff_mask_w) | ({DATA_WIDTH{src1[DATA_WIDTH/2-1]}} & (~eff_mask_w));
assign srl_result = alu_len_dw ? srlw_result_t : srl_result_t;
assign sra_result = alu_len_dw ? sraw_result_t : sra_result_t;
assign srla_result = alu_func7[5] ? sra_result : srl_result;

//or
wire [DATA_WIDTH-1:0] or_result;
assign or_result = src1 | src2;

//and
wire [DATA_WIDTH-1:0] and_result;
assign and_result = src1 & src2;

//mul
wire [2*DATA_WIDTH-1:0] mul_result;
wire mul_src1_sign, mul_src2_sign;
wire mul_cal, mul_ready, mul_out_valid, mul_valid;
ysyx_22040729_Reg #(1, 1'b0) mul_cal_inst (clock, reset, exe_flow, mul_cal, exe_flow | mul_out_valid);
wire mul_busy = {alu_func7[0],alu_func3[2]}==2'b10 & mul_cal & !mul_out_valid;
assign mul_valid = {alu_func7[0],alu_func3[2]}==2'b10 & mul_cal & mul_ready;
assign mul_src1_sign = alu_func3[1:0]!=2'b11;
assign mul_src2_sign = !alu_func3[1];
ysyx_22040729_EXE_ALU_Multiplier #(DATA_WIDTH) multiplier_inst(
  .clock          (clock),
	.reset          (reset),
	.mul_valid      (mul_valid),
	.flush          (exe_flow),
	.mulw	          (alu_len_dw),
	.mul_signed     ({mul_src1_sign, mul_src2_sign}),
	.multiplicand   (src1),
	.multiplier     (src2),
	.mul_ready      (mul_ready),
	.out_valid      (mul_out_valid),
	.result_hi      (mul_result[127:64]),
	.result_lo      (mul_result[63:0])
);

//div
wire [DATA_WIDTH-1:0] div_quo, div_rem, div_quo_temp, div_rem_temp, div_dividend, div_divisor;
wire div_sign;
wire div_cal, div_ready, div_out_valid, div_valid;
ysyx_22040729_Reg #(1, 1'b0) div_cal_inst (clock, reset, exe_flow, div_cal, exe_flow | div_out_valid);
wire div_busy = {alu_func7[0],alu_func3[2]}==2'b11 & div_cal & !div_out_valid;
assign div_valid = {alu_func7[0],alu_func3[2]}==2'b11 & div_cal & div_ready;

ysyx_22040729_EXE_ALU_Divider #(DATA_WIDTH, DATA_WIDTH) divider_inst( 
  .clock       (clock),
  .reset       (reset),
  .dividend    (div_dividend),
  .divisor     (div_divisor),
  .div_valid   (div_valid),
  //.divw        (alu_len_dw),
  .flush       (exe_flow),
  .div_ready   (div_ready),
  .out_valid   (div_out_valid),
  .quotient    (div_quo_temp),
  .remainder   (div_rem_temp)
);
assign div_sign = !alu_func3[0];
assign div_dividend = div_sign & src1[DATA_WIDTH-1] ? ~src1 + 1'b1 : src1;
assign div_divisor  = div_sign & src2[DATA_WIDTH-1] ? ~src2 + 1'b1 : src2;
assign div_quo      = (div_sign & (src1[DATA_WIDTH-1] ^ src2[DATA_WIDTH-1])) ? ~div_quo_temp + 1'b1 : div_quo_temp;
assign div_rem      = (div_sign & src1[DATA_WIDTH-1]) ? ~div_rem_temp + 1'b1 : div_rem_temp;

assign alu_busy = mul_busy | div_busy;

//result_rbasic
MuxKey #(16, 4, DATA_WIDTH) mux_rbasic (
  result_rbasic,
  {alu_func7[0],alu_func3}, {
    4'b0000, alu_func7[5] ? sub_result[DATA_WIDTH-1:0] : add_result[DATA_WIDTH-1:0], //add sub
    4'b0001, sll_result,    //sll
    4'b0010, slt_result,    //slt
    4'b0011, sltu_result,   //sltu
    4'b0100, xor_result,    //xor
    4'b0101, srla_result,   //srl(a)
    4'b0110, or_result,     //or
    4'b0111, and_result,    //and
    4'b1000, mul_result[DATA_WIDTH-1:0],              //mul
    4'b1001, mul_result[2*DATA_WIDTH-1:DATA_WIDTH],   //mulh
    4'b1010, mul_result[2*DATA_WIDTH-1:DATA_WIDTH],   //mulhsu
    4'b1011, mul_result[2*DATA_WIDTH-1:DATA_WIDTH],   //mulsu
    4'b1100, div_quo,                                 //div
    4'b1101, div_quo,                                 //divu
    4'b1110, div_rem,                                 //rem
    4'b1111, div_rem}                                 //remu
);

//result_ibasic
MuxKey #(8, 3, DATA_WIDTH) mux_ibasic (
  result_ibasic,
  alu_func3, {
    3'b000, add_result[DATA_WIDTH-1:0],  //addi
    3'b001, sll_result,                  //slli
    3'b010, slt_result,                  //slti
    3'b011, sltu_result,                 //sltui
    3'b100, xor_result,                  //xori
    3'b101, srla_result,                 //srl(a)i
    3'b110, or_result,                   //ori
    3'b111, and_result}                  //andi
);



endmodule
module ysyx_22040729_EXE_ALU_Divider#(
	parameter	DIVISOR_WIDTH		= 32,
	parameter	DIVIDEND_WIDTH		= 32
)(
	input  clock,
    input  reset,
	input  [DIVISOR_WIDTH-1:0]	dividend,
	input  [DIVIDEND_WIDTH-1:0]	divisor,
    input  div_valid,
    //input  divw,
    input  flush,
    output div_ready,
    output out_valid,
	output [DIVIDEND_WIDTH-1:0]	quotient,
	output [DIVISOR_WIDTH-1:0]	remainder
);
wire [DIVISOR_WIDTH+DIVIDEND_WIDTH-1:0] dividend_shift, dividend_shift_next;
wire [DIVISOR_WIDTH-1:0]  divisor_shift;
wire [$clog2(DIVIDEND_WIDTH):0] cnt;
wire div_doing;
wire div_done = cnt==DIVIDEND_WIDTH;
assign div_ready = ~div_doing;
assign out_valid = div_done & div_doing;

ysyx_22040729_Reg #(DIVISOR_WIDTH+DIVIDEND_WIDTH, {(DIVISOR_WIDTH+DIVIDEND_WIDTH){1'b0}}) dividend_shift_inst (clock, reset, dividend_shift_next, dividend_shift, div_valid | (div_doing&!div_done));
ysyx_22040729_Reg #(DIVISOR_WIDTH, {(DIVISOR_WIDTH){1'b0}}) divisor_shift_inst (clock, reset, divisor, divisor_shift, div_valid);
ysyx_22040729_Reg #($clog2(DIVIDEND_WIDTH)+1, {($clog2(DIVIDEND_WIDTH)+1){1'b0}}) cnt_inst (clock, reset,
	div_valid ? {($clog2(DIVIDEND_WIDTH)+1){1'b0}} : cnt+1'b1, cnt, div_valid | div_doing);
ysyx_22040729_Reg #(1, 1'b0) div_doing_inst (clock, reset, div_valid & div_ready & ~flush, div_doing, (div_valid & div_ready) | flush | div_done);
assign dividend_shift_next = div_valid ? {{(DIVISOR_WIDTH){1'b0}}, dividend} :
                             subres[DIVISOR_WIDTH] ? {dividend_shift[DIVISOR_WIDTH+DIVIDEND_WIDTH-2:0], 1'b0} :
							 {subres[DIVISOR_WIDTH-1:0], dividend_shift[DIVIDEND_WIDTH-2:0], 1'b1};

wire [DIVISOR_WIDTH:0] subres;
assign subres = {dividend_shift[DIVISOR_WIDTH+DIVIDEND_WIDTH-2:DIVIDEND_WIDTH-1]} - divisor_shift;//unsigned substract
assign remainder = dividend_shift[DIVISOR_WIDTH+DIVIDEND_WIDTH-1:DIVIDEND_WIDTH];
assign quotient  = dividend_shift[DIVIDEND_WIDTH-1:0];

/*
//==============================================================================================
//======								define signal									========
//==============================================================================================
    reg	[DIVISOR_WIDTH+DIVIDEND_WIDTH-1:0]		tempa	;	
    reg	[DIVISOR_WIDTH+DIVIDEND_WIDTH-1:0]		tempb	;	
	integer	i;
//==============================================================================================
//======                               behave of RTL                                    ========
//==============================================================================================
	//--------------------------------------------------------------------
	//------    	Calculation 						           	------
	//--------------------------------------------------------------------
	always @(dividend or divisor)begin 
		if(divisor != 0)begin
			tempa = {{DIVIDEND_WIDTH{1'b0}},dividend};  
			tempb = {divisor,{DIVISOR_WIDTH{1'b0}}};  
			for(i = 0;i < DIVISOR_WIDTH;i = i + 1)begin
				tempa = {tempa[0 +: (DIVISOR_WIDTH+DIVIDEND_WIDTH-1)],1'b0};
				if(tempa[DIVISOR_WIDTH +: DIVIDEND_WIDTH] >= divisor)begin
					tempa = tempa - tempb + 1;
				end else begin
					tempa = tempa;
				end
			end
			quotient 	= tempa[0 +: DIVISOR_WIDTH];
			remainder 	= tempa[DIVISOR_WIDTH +: DIVIDEND_WIDTH];
			//$display("@%10t : dividend is %d,divisor is %d/n", $time,dividend,divisor);
			//$display("@%10t : quotient is %d,remainder is %d/n", $time,quotient,remainder);
		end else begin
			quotient	= {DIVISOR_WIDTH{1'b0}};
			remainder	= {DIVIDEND_WIDTH{1'b0}};
			tempa = 0;
			tempb = 0;
			//$display("@%10t : divisor is not a valid value ...", $time);
		end
	end
	*/
	
endmodule
module ysyx_22040729_EXE_ALU_Multiplier#(
	 parameter	Multiplier_WIDTH		= 64
)(
	input	wire         clock		,//	时钟信号
	input	wire         reset		,//	复位信号（高有效）
	input	wire         mul_valid	,//	为高表示输入的数据有效，如果没有新的乘法输入，在乘法被接受的下一个周期要置低
	input	wire         flush		,//	为高表示取消乘法
	input	wire         mulw		,//	为高表示是 32 位乘法
	input	wire  [1:0]  mul_signed	,//	2’b11（signed x signed）；2’b10（signed x unsigned）；2’b00（unsigned x unsigned）；
	input	wire  [Multiplier_WIDTH-1:0]   multiplicand	,//	被乘数，xlen 表示乘法器位数
	input	wire  [Multiplier_WIDTH-1:0]   multiplier	,//	乘数
	output	wire         mul_ready	,//	为高表示乘法器准备好，表示可以输入数据
	output	wire         out_valid	,//	为高表示乘法器输出的结果有效
	output	wire  [Multiplier_WIDTH-1:0]   result_hi,//	高 xlen bits 结果
	output	wire  [Multiplier_WIDTH-1:0]   result_lo //	低 xlen bits 结果
);

wire[Multiplier_WIDTH*2+3:0] x_ext;
wire[Multiplier_WIDTH+2:0]   y_ext;//for booth:++

assign x_ext = mulw ? {(mul_signed[1] ? {(Multiplier_WIDTH+36){multiplicand[31]}} : {(Multiplier_WIDTH+36){1'b0}}), multiplicand[31:0]} :
						{(mul_signed[1] ? {(Multiplier_WIDTH+4){multiplicand[63]}} : {(Multiplier_WIDTH+4){1'b0}}), multiplicand};
assign y_ext = mulw ? {(mul_signed[0] ? {34{multiplier[31]}} : 34'b0), multiplier[31:0], 1'b0} :
						{(mul_signed[0] ? {2{multiplier[63]}} : 2'b0), multiplier, 1'b0};

wire mul_doing;
wire [Multiplier_WIDTH*2+3:0] res;
wire [Multiplier_WIDTH+2  :0] y_shift;
wire [Multiplier_WIDTH*2+3:0] x_shift;
wire [5:0]                    cnt;

wire[131:0] x_comp = (~x_shift) + 1;
wire[131:0] z = {132{y_shift[2:0] == 3'b000 || y_shift[2:0] == 3'b111}} & 132'b0  |
  				{132{y_shift[2:0] == 3'b001 || y_shift[2:0] == 3'b010}} & x_shift |
  				{132{y_shift[2:0] == 3'b101 || y_shift[2:0] == 3'b110}} & x_comp  |
  				{132{y_shift[2:0] == 3'b011}} & {x_shift[130:0], 1'b0}            |
  				{132{y_shift[2:0] == 3'b100}} & {x_comp[130:0], 1'b0};

assign mul_ready = ~mul_doing;
wire mul_done = ~|y_shift | cnt==(mulw?6'd17:6'd33);
assign out_valid = mul_done & mul_doing;
ysyx_22040729_Reg #(Multiplier_WIDTH*2+4, {(Multiplier_WIDTH*2+4){1'b0}}) x_shift_inst (clock, reset, mul_valid ? x_ext : x_shift<<2, x_shift, mul_valid | mul_doing);
ysyx_22040729_Reg #(Multiplier_WIDTH+3, {(Multiplier_WIDTH+3){1'b0}}) y_shift_inst (clock, reset, mul_valid ? y_ext : y_shift>>2, y_shift, mul_valid | mul_doing);
ysyx_22040729_Reg #(Multiplier_WIDTH*2+4, {(Multiplier_WIDTH*2+4){1'b0}}) res_inst (clock, reset, mul_valid ? {(Multiplier_WIDTH*2+4){1'b0}} : z + res, res, mul_valid | (mul_doing&!mul_done));
ysyx_22040729_Reg #(6, 6'b0) cnt_inst (clock, reset, mul_valid ? 6'b0 : cnt+1'b1, cnt, mul_valid | mul_doing);
ysyx_22040729_Reg #(1, 1'b0) mul_doing_inst (clock, reset, mul_valid & mul_ready & ~flush, mul_doing, (mul_valid & mul_ready) | flush | mul_done);

 
assign result_hi = res[127:64];
assign result_lo = res[63:0];

	
endmodule
/*========================================================
#
# Author: Steven
#
# QQ : 935438447 
#
# Last modified: 2022-04-20 19:05
#
# Filename: Reg.v
#
# Description: The standard reg module 
#
=========================================================*/
module ysyx_22040729_Reg #(WIDTH = 1, RESET_VAL = 0) (
  input clk,
  input rst,
  input [WIDTH-1:0] din,
  output reg [WIDTH-1:0] dout,
  input wen
);
  always @(posedge clk) begin
    if (rst) dout <= RESET_VAL;
    else if (wen) dout <= din;
  end
endmodule
/*========================================================
#
# Author: Steven
#
# QQ : 935438447 
#
# Last modified: 2022-04-20 19:33
#
# Filename: MuxKey.v
#
# Description: 不带默认值的选择器模板
#
=========================================================*/
module MuxKey #(NR_KEY = 2, KEY_LEN = 1, DATA_LEN = 1) (
  output [DATA_LEN-1:0] out,
  input [KEY_LEN-1:0] key,
  input [NR_KEY*(KEY_LEN + DATA_LEN)-1:0] lut
);
  ysyx_22040729_MuxKeyInternal #(NR_KEY, KEY_LEN, DATA_LEN, 0) i0 (out, key, {DATA_LEN{1'b0}}, lut);
endmodule

/*========================================================
#
# Author: Steven
#
# QQ : 935438447 
#
# Last modified:	2022-04-20 19:35
#
# Filename:		MuxKeyInternal.v
#
# Description: The standard Mux
#
=========================================================*/
module ysyx_22040729_MuxKeyInternal #(NR_KEY = 2, KEY_LEN = 1, DATA_LEN = 1, HAS_DEFAULT = 0) (
  output reg [DATA_LEN-1:0] out,
  input [KEY_LEN-1:0] key,
  input [DATA_LEN-1:0] default_out,
  input [NR_KEY*(KEY_LEN + DATA_LEN)-1:0] lut
);

  localparam PAIR_LEN = KEY_LEN + DATA_LEN;
  wire [PAIR_LEN-1:0] pair_list [NR_KEY-1:0];
  wire [KEY_LEN-1:0] key_list [NR_KEY-1:0];
  wire [DATA_LEN-1:0] data_list [NR_KEY-1:0];

  generate
    for (genvar n = 0; n < NR_KEY; n = n + 1) begin
      assign pair_list[n] = lut[PAIR_LEN*(n+1)-1 : PAIR_LEN*n];
      assign data_list[n] = pair_list[n][DATA_LEN-1:0];
      assign key_list[n]  = pair_list[n][PAIR_LEN-1:DATA_LEN];
    end
  endgenerate

  reg [DATA_LEN-1 : 0] lut_out;
  reg hit;
  integer i;
  always @(*) begin
    lut_out = 0;
    hit = 0;
    for (i = 0; i < NR_KEY; i = i + 1) begin
      lut_out = lut_out | ({DATA_LEN{key == key_list[i]}} & data_list[i]);
      hit = hit | (key == key_list[i]);
    end
    if (!HAS_DEFAULT) out = lut_out;
    else out = (hit ? lut_out : default_out);
  end
endmodule

/*========================================================
#
# Author: Steven
#
# QQ : 935438447 
#
# Last modified: 2022-04-20 19:33
#
# Filename: MuxKeyWithDefault.v
#
# Description: 带默认值的选择器模板
#
=========================================================*/
module MuxKeyWithDefault #(NR_KEY = 2, KEY_LEN = 1, DATA_LEN = 1) (
  output [DATA_LEN-1:0] out,
  input [KEY_LEN-1:0] key,
  input [DATA_LEN-1:0] default_out,
  input [NR_KEY*(KEY_LEN + DATA_LEN)-1:0] lut
);
  ysyx_22040729_MuxKeyInternal #(NR_KEY, KEY_LEN, DATA_LEN, 1) i0 (out, key, default_out, lut);
endmodule
